DICOM de-identification design#
This document specifies the DICOM de-identification engine that will replace pymedphys.dicom.anonymise and the experimental pseudonymisation module, and records the decisions behind it. A run now de-identifies, checks, and reports a collection, but no preset is enabled until the first supported release; the register records what is implemented. The current tools share one engine in lib/pymedphys/_dicom/anonymise/, do not implement a DICOM confidentiality profile, and have the limitations listed in DICOM de-identification.
Pull requests for this work are listed in the tracking issue. A pull request that changes a decision updates this document, the user documentation, and any affected code in the same change.
Scope#
The engine de-identifies a collection of DICOM instances as a unit and preserves the references between them. The library API, the command-line interface, and the Streamlit app all call the same engine.
The target coverage is:
Objects: CT, MR, PET, RT Structure Set, RT Plan, RT Dose, RT Beams Treatment Record, RT Image, spatial registration, segmentation, and Structured Reports: radiation dose reports, which the maintainer added on 25 October 2026, and every other Structured Report IOD of PS3.3 Section A.35, which the maintainer added later that day; and the other RT IODs, which the maintainer added on 31 October 2026: RT Ion Plan, RT Ion Beams Treatment Record, RT Brachy Treatment Record, RT Treatment Summary Record, Enhanced RT Image, Enhanced Continuous RT Image, and the 16 second-generation RT IODs; and the other IODs that radiotherapy exports carry, which the maintainer added the same day, each to be supported with its own evidence: Surface Segmentation, the Secondary Capture IODs, Computed Radiography and Digital X-Ray, Nuclear Medicine, Encapsulated PDF, Parametric Map and Real World Value Mapping, and Presentation States.
Profile and options: the Basic Application Level Confidentiality Profile with each option of Table E.1-1, as the maintainer decided on 12 October 2026: Retain Safe Private, Retain UIDs, Retain Device Identity, Retain Institution Identity, Retain Patient Characteristics, Retain Longitudinal Temporal Information with Full Dates or with Modified Dates, Clean Descriptors, Clean Structured Content, and Clean Graphics, and with the Clean Pixel Data and Clean Recognizable Visual Features Options, which the table leaves out (D-011).
Evidence: a generated conformance statement, a requirements register traced to tests, and published benchmark results (D-018).
The first supported release covers the Basic Profile with each option listed above, through every preset (Presets) and through custom option sets of them (D-033), as the maintainer decided on 25 October 2026, with a run-scoped key, for instances of the CT, MR, and PET image IODs, including their Enhanced, Legacy Converted Enhanced, and colour variants and the For Processing SOP Classes, of MR Spectroscopy, of Nuclear Medicine Image, of RT Structure Set, RT Plan, RT Dose, RT Image, Enhanced RT Image, Enhanced Continuous RT Image, RT Segment Annotation, RT Radiation Set, C-Arm Photon-Electron Radiation, Tomotherapeutic Radiation, Robotic-Arm Radiation, RT Beams Delivery Instruction, RT Brachy Application Setup Delivery Instruction, RT Radiation Set Delivery Instruction, RT Beams Treatment Record, RT Ion Plan, RT Ion Beams Treatment Record, RT Brachy Treatment Record, and RT Treatment Summary Record, of Spatial Registration and Deformable Spatial Registration, of Segmentation and Surface Segmentation, and of the X-Ray Radiation Dose SR, Enhanced X-Ray Radiation Dose SR, Radiopharmaceutical Radiation Dose SR, Patient Radiation Dose SR, Basic Text SR, Enhanced SR, Comprehensive SR, Comprehensive 3D SR, Extensible SR, Key Object Selection Document, Mammography CAD SR, Chest CAD SR, Colon CAD SR, Procedure Log, Spectacle Prescription Report, Macular Grid Thickness and Volume Report, and Waveform Annotation SR, of Parametric Map, Real World Value Mapping, and Encapsulated PDF, and of the Grayscale, Color, Pseudo-Color, Blending, XA/XRF Grayscale, and Variable Modality LUT Softcopy Presentation States, uncompressed or in a transfer syntax that encapsulates Pixel Data that pydicom’s decoding plugins decode (D-010). The maintainer decided on 25 October 2026 to bring the other objects of the target coverage into the first supported release too, “so long as this is an expansion of scope”: RT Beams Treatment Record, RT Image, the two registrations, and Segmentation, which it now supports (D-010); and the radiation dose reports and every other Structured Report IOD, of which it now supports the X-Ray, Enhanced X-Ray, Radiopharmaceutical, and Patient Radiation Dose SRs, the Basic Text, Enhanced, Comprehensive, Comprehensive 3D, and Extensible SRs, and the Key Object Selection Document, Mammography CAD SR, Chest CAD SR, Colon CAD SR, Procedure Log, Spectacle Prescription Report, Macular Grid Thickness and Volume Report, and Waveform Annotation SR. On 31 October 2026 the maintainer decided to bring the 22 other RT IODs of the target coverage into the first supported release too, in this order: RT Ion Plan and RT Ion Beams Treatment Record; RT Brachy Treatment Record and RT Treatment Summary Record; Enhanced RT Image and Enhanced Continuous RT Image; and the 16 second-generation RT IODs. Each is supported in a change of its own, after its attributes are reviewed (D-010, D-022); RT Ion Plan, RT Ion Beams Treatment Record, RT Brachy Treatment Record, RT Treatment Summary Record, Enhanced RT Image, Enhanced Continuous RT Image, RT Segment Annotation, RT Radiation Set, the C-Arm Photon-Electron, Tomotherapeutic, and Robotic-Arm Radiations, and the RT Beams, RT Brachy Application Setup, and RT Radiation Set Delivery Instructions now are. The same day the maintainer decided to bring the other IODs that RT exports carry into the first supported release too, each with its own evidence: Surface Segmentation; Computed Radiography and Digital X-Ray; Nuclear Medicine; Parametric Map and Real World Value Mapping; the Secondary Capture IODs; the Presentation States; and Encapsulated PDF. Surface Segmentation, Nuclear Medicine Image, Parametric Map, Real World Value Mapping, the six softcopy Presentation States, and Encapsulated PDF now are, and the run holds each Surface Segmentation under Clean Recognizable Visual Features, since no preview of the QC pack yet draws its meshes (D-010, D-017). Each preset and each option is enabled once its behaviour is implemented and validated for this scope, and the release waits until every one is, rather than shipping basic and basic-clean-descriptors first, as the maintainer also decided on 25 October 2026 (Roadmap). Some instances of these IODs are still sequestered under basic and basic-clean-descriptors: every Enhanced PET Image instance and every softcopy Presentation State that conforms to its IOD (D-020), and any instance whose Referenced Performed Procedure Step Sequence has no UID to replace, or whose required ICC Profile is not an RGB profile (D-021); and every Structured Report or Key Object Selection Document whose content tree Clean Structured Content does not keep (D-047). Under every preset, so is every Presentation State that holds graphic annotations or an overlay (D-010), and, under every policy, every Encapsulated PDF that holds its document, which Table E.1-1 gives D and no reviewed rule gives a dummy value (D-010). A compressed instance is also sequestered where the plugin pinned to its transfer syntax is not installed, or where its frames or codestreams fail the engine’s checks (Architecture items 2 and 7). Later releases extend it to the rest of the target coverage, each with its own evidence.
The first supported release ships the library API and the command line, which is a thin layer over the library: batch users need the command line, and the surface to validate stays small. A library alone was rejected because most users will not script it. The command prints a summary of counts, statuses, and reason names, never a source value or source path (the only directories it names are the release directory, its staging area, and the QC destination), and its exit status tells a script the outcome: 0 when every input was released or is a duplicate of one released, 1 when the release was published but an input was refused, sequestered, or held for review, 2 when its arguments cannot be parsed, 3 when the run did not start, its first pass stopped it for a study whose instances name several patients, which an opt-in sequesters instead (D-026), or its QC pack could not be written, 4 when its staging area was left behind, which outranks every other status since the staging area may still identify people and must be deleted by hand, and 70 for any other failure, reported by the exception’s type alone. The app comes in a later release, because pymedphys gui has no login and can serve its apps to other computers, so a de-identification app needs its own design for keys and QC material. Until the new app ships, the legacy pseudonymisation app stays, with its limitation banner (D-019).
The following are not supported. Input that needs them is rejected or sequestered, without a conformance claim:
the second-generation RT objects, until each is supported (D-010);
Structured Reports until each IOD is supported, the volumetric, advanced blending, and waveform Presentation States until each is supported, and Private SOP Classes (D-010);
legal determinations, since whether data are anonymous depends on the release context, not on the software.
Until a preset or option is enabled, the engine refuses a run that selects it (D-033), and it refuses by name an option whose actions it does not yet apply (D-011). Under Clean Pixel Data, it blacks out the text it finds and holds each instance it cleans for review, claiming the option only for an instance without top-level pixel data or whose regions a reviewer approved on a later run (D-037, D-048). Under Clean Recognizable Visual Features, it holds for review each instance that can show a face and that a reviewer has not found free of one (D-046).
Terminology and claims#
The engine performs de-identification, the term used by DICOM PS3.15 and the MIDI Task Group report. Anonymisation and pseudonymisation are not separate features: both apply the same transformation. They differ in whether anyone retains a means of re-identification, such as a project key or a crosswalk, and in which indirect identifiers the selected options keep.
Whether data are anonymous is a legal conclusion about the data in their release context (for example GDPR Recital 26), which software cannot establish. The Australian Privacy Act 1988 (Cth) s 6(1) and the HIPAA Privacy Rule (45 CFR 164.514) use “de-identified” for such a legal status.
In code, command-line output, reports, and documentation:
Describe output only as “de-identified in accordance with the DICOM PS3.15 edition Basic Application Level Confidentiality Profile with options”, and only after validating its effective policy and content against that profile and those options (D-011). Never use “de-identified” without that qualification.
Never describe output as “anonymised”.
Where a key or crosswalk is retained, state that the data remain pseudonymised personal data for whoever holds it, and that any other recipient needs its own assessment.
An instance is sequestered when the engine does not write it to the release output, whether it is set aside before de-identification or fails a check during or after it: the run report lists it by opaque identifiers only, it is excluded from the conformance claim, and its source is left unchanged.
Standards basis#
Role |
Source |
|---|---|
Normative rules |
DICOM PS3.15 Annex E, edition 2026d: E.1.1 (de-identifier), E.1.3 (conformance statement), E.2 (Basic Profile), E.3 (Options), and Tables E.1-1, E.1-1a, E.3.4-1, and E.3.10-1 |
Supporting DICOM parts |
PS3.3 (attribute Types per IOD), PS3.4 (Table B.5-1, the IOD of each Storage SOP Class), PS3.5 (UID encoding, registration, and UUID-derived UIDs), PS3.6 (data dictionary and well-known UIDs), PS3.7 (Implementation Class UIDs), PS3.10 (File Meta Information), PS3.16 (Tables 8-1 and 8-2 coding schemes and their UIDs, CID 7050 de-identification methods, and CID 7005 contributing equipment purposes) |
Best practice |
Clunie DA et al., Report of the Medical Image De-Identification (MIDI) Task Group: Best Practices and Recommendations, 7 February 2025, arXiv:2303.10473 |
Validation |
NCI MIDI synthetic-identifier datasets, answer keys, and validation script (D-018); |
Governance context (documentation only) |
GDPR Article 4(5) and Recital 26; CJEU C-413/23 P EDPS v SRB (4 September 2025); UK ICO anonymisation guidance; Privacy Act 1988 (Cth) and OAIC de-identification guidance; ISO 25237:2017 |
Where this document relies on an informative Note in PS3.15 or on a MIDI recommendation, the choice it supports is a design decision, not a conformance requirement. Browsing links follow the current edition; the table generator uses the pinned publication (D-001).
Requirements register#
The requirements register traces the standard’s “shall” statements and the MIDI best practices to the decisions, code, and tests that satisfy them. It is lib/pymedphys/_dicom/deidentify/requirements.toml, curated by hand, and records:
every paragraph of PS3.15 Annex E in the pinned edition that contains “shall”, outside Notes and tables, verbatim with any list it introduces and a link to the paragraph;
the 18 best practices of MIDI §1.6, summarised in PyMedPhys’s words.
A test checks that its PS3.15 entries are exactly the Annex E paragraphs that the table generator extracts from the pinned edition, with the same sections, links, and text, in the standard’s order (D-001).
Like the generated tables, the file carries the attribution “DICOM PS3.15 2026d, © NEMA” (D-001).
Identifiers are stable and never reused. PS3.15-E.1.1-01 numbers the paragraphs of a section in the standard’s order, and MIDI-BP-01 to MIDI-BP-18 follow the report’s numbering. Each entry cites the decisions that address it and has one of these statuses:
Status |
Meaning |
Entry also records |
|---|---|---|
|
In scope, not yet implemented |
The milestone that completes it |
|
Partly implemented |
Modules so far, what remains, and the milestone that completes it; tests so far cite it |
|
Met for the supported scope |
Modules; the tests that show it cite it |
|
Not supported, such as an Option that Scope excludes |
A note saying why |
|
Outside PyMedPhys’s role, such as re-identification |
A note saying why |
A pull request that implements part of a requirement updates its entry in the same change.
A test cites the requirements it shows are met with a marker on the test function or its
Testclass,@pytest.mark.deid_requirement("PS3.15-E.1.1-01"), and the register does not list tests. The register’s tests for a requirement are those that cite it, read from the tests’ source without importing them, in the order of their files and then of their definitions. A note may be written one sentence per line, and its lines are joined with spaces. Both keep pull requests that add tests or sentences to the same requirement from editing the same lines of the register.pymedphys._dicom.deidentify.requirements.load_requirementsrejects malformed or inconsistent entries, such as an implemented requirement without tests or an exclusion without a note, and a test that cites a requirement the register does not record. Tests check that every cited decision and module exists, that pytest collects every citing test and sees the same citations as the source, and that the register follows the edition of the generated tables.A new edition updates the register with the tables, after comparing it with every Annex E page of that edition: add paragraphs, update changed text, and remove deleted paragraphs without reusing their identifiers.
Normative text without “shall”, such as the paragraphs after Table E.1-1a on actions for Sequences and on Options overriding the Profile, gets entries when the engine implements it.
The traceability matrix for each release (D-018) is generated from the register by
pymedphys dev deid-matrix, as Markdown, and is not committed. It summarises the entries by status and source, and lists each requirement with its milestone, decisions, modules, and traced tests, the exclusions with the reason for each, and the remaining work with its milestone. Given pytest JUnit XML reports with--junit, one for each tested environment, it gives each traced test’s outcome. A requirement’s traced tests pass only when every case of every test that traces it passed in every report: a skipped case, or a test or case that one report lacks although another ran it, leaves them incomplete; passing tests do not make a partial requirement met.--checkexits with status 1 when a traced test failed, was skipped, or did not run. Each release renders the matrix from the reports of every environment in the unit-test matrix, checks it, and attaches it to the GitHub release.
Architecture#
The engine will live in lib/pymedphys/_dicom/deidentify/, with its public API in pymedphys.dicom. Its components are listed below; they are not a pull request sequence.
Generated standard tables. Table E.1-1 with every option column; Tables E.1-1a and E.3.10-1; the rows of Table E.3.4-1 whose concept names are coded by DICOM, SNOMED CT, or LOINC; the PS3.6 data dictionary (Table 6-1), with each attribute’s keyword, VR, VM, and retirement; the PS3.6 Annex A registries of UIDs, well-known frames of reference, and the UIDs of context groups and templates (Tables A-1 to A-4); the PS3.16 coding schemes (Tables 8-1 and 8-2) and context groups CID 7050 and CID 7005; the PS3.4 Storage SOP Classes with the IOD of each (Table B.5-1); and, from PS3.3, the modules of every composite IOD that the pin does not leave out, each table of PS3.3 Annex A titled with an IOD’s name and “IOD Modules”, with the IOD’s Functional Group Macros where its modules include them, and the attribute tables of those modules and Functional Group Macros and of the macros they include, which give each attribute’s Type (D-001).
Rule layers. Rules apply in this order: generated tables (L1), reviewed supplementary rules (L2), then validated user rules (L3).
L1 gives each attribute of Table E.1-1 the action of the selected options that give one, and otherwise the Profile’s, since “a requirement for an Option, when implemented, overrides any requirement for the underlying Profile” (E.1.1). E.3.6 specifies Retain Longitudinal Temporal Information with Full Dates and with Modified Dates as mutually exclusive, so a selection of both is rejected. Otherwise PS3.15 defines no precedence between options, so an attribute to which two selected options give different actions has no L1 action and is reported as a conflict for policy validation (D-007, D-011). In 2026d, the only such options are Retain Device Identity and Modified Dates, on eleven attributes. Policy validation rejects every conflict except these, which only the
tps-importpreset resolves (D-011).L2 covers attributes that Table E.1-1 omits but the de-identifier remains responsible for (E.1.1, Note 1 after Table E.1-1a). These are person names, and dates and times (D-023), by VR; text attributes, such as Beam Name, Dose Comment, and Wedge ID, by a reviewed list, with removal by Type for any it does not cover (D-022); URI and URL attributes, Series Number, and some sequences and binary attributes, by reviewed rules (D-022); the role of every UI attribute (D-003); and the role of every temporal attribute (D-007). A test fails if the pinned dictionary contains a date, time, datetime, person name, or UI attribute with no rule.
The L2 file
supplementary_actions.tomlgives an action of Table E.1-1a, with a note saying why, to attributes that Table E.1-1 omits, other than UI attributes, which have roles instead (D-003). Every person name that the table omits has one: in 2026d, Secondary Reviewer Name and Evaluator Name, which PS3.6 marks DICONDE and no supported IOD uses, get X/Z/D, and the retired Document Author (Trial) gets X, as the table gives the other (Trial) person names. Burned In Annotation and Recognizable Visual Features are kept (K), as D-015 requires. So does every text attribute that the table omits and a supported IOD uses (D-022). URN Code Value and Coding Scheme URL are kept (K) (D-022). Every date, time, and datetime that the table omits has one too, besides its role (D-007, D-023). Like a row of the table, a rule can also give an action under an option, which overrides its Basic Profile action when that option is selected: for a text attribute, only C under Clean Descriptors and K under Retain Device Identity; for a date, time, or datetime, only K under Retain Longitudinal Temporal Information with Full Dates and C under Modified Dates; and only over an action that removes or replaces the value. Policy composition resolves these option actions as it does the table’s, and rejects a rule to which two selected options give different actions (D-011). The file never covers an attribute that Table E.1-1 lists.L2 only strengthens L1. It never retains a value that L1 removes, replaces, or cleans, unless a selected option permits it.
Each element is decoded with the VR that the pinned dictionary gives its attribute, not with pydicom’s dictionary, and then handled by its rule. A value of VR UN is decoded as Implicit VR Little Endian, whatever the transfer syntax (PS3.5 Section 6.2.2), and as a sequence only if items fill it, since pydicom reads malformed items without complaint. The element decoder, the first pass’s reference records, and the pixel data risk indicators pass each sequence value that pydicom holds undecoded through
pymedphys._dicom.deidentify.sequences.decode_itemsbefore they read its items, which has pydicom decode it only oncefile_layout.reads_as_itemsfinds that items fill it, and each refuses one that is not only items by the sequence’s path, without quoting a value; a test keeps any other module of the engine from having pydicom decode items itself. A VR in the file must be one that the dictionary gives, and must not contradict the one that the standard decides of alternatives. Of alternatives, US or SS follows Pixel Representation (0028,0103) in the nearest data set that has it (PS3.3 Sections C.7.5.1, C.7.6.3, and C.11.1.1.1), but for LUT Descriptor (0028,3002) in VOI LUT Sequence (0028,3010), PS3.3 Section C.11.2.1.1 has the input to the VOI LUT decide it: Pixel Representation “if there is no Modality LUT or Rescale Slope and Intercept specified”, SS “if the possible output range after application of the Rescale Slope and Intercept may be signed”, as Hounsfield Units always can, and “US otherwise”, which includes the output of a Modality LUT, “always unsigned” (Section C.11.1.1.1). There, in explicit VR, either is accepted, since “the explicit VR actually used is dictated by the VR needed to represent the second Value”. Section C.7.6.3.1.5 says the same of the Red, Green, and Blue Palette Color Lookup Table Descriptors (0028,1101-1103), adding that it “will be consistent with Pixel Representation”, so in explicit VR either is accepted there too, even where it is not, as in an icon image (0088,0200) whose own Pixel Representation, or its image’s, says otherwise; Pixel Representation decides it only without a VR in the file. In Presentation LUT Sequence (2050,0010), “the Value Representation of the second Value is always US” (Section C.11.4.1). Whatever the VR, “the first and third values are always by definition interpreted as unsigned” (Sections C.7.6.3.1.5, C.11.1.1.1, and C.11.2.1.1), so they are decoded and written as unsigned where the VR is SS, and a table of 40000 entries keeps its count. Real World Value First Value Mapped (0040,9216) and Last Value Mapped (0040,9211) are SS for floating point pixel data (Section C.7.6.16.2.11.1.1), which the first supported release’s IODs do not have, so without a VR in the file they cannot be decoded where Pixel Representation is absent. Without a VR in the file, OB or OW, and US or OW, are OW, as PS3.5 Section A.1 gives Pixel Data, Overlay Data, and Waveform Data, whose bytes are the same either way; and in explicit VR, Pixel Data is OB if encapsulated and OW where Bits Allocated (0028,0100) is more than 8 (Sections A.2 and A.4). An element whose VR is not one the dictionary gives or contradicts the one the standard decides, whose alternatives nothing decides, or whose value does not decode exactly with its VR, such as a DS that is not a number, cannot be decoded. Elements are decoded from data sets asdcmreadreturned them: once pydicom has decoded an element read from a file, as indexing, attribute access,get, and iteration do, it holds no encoded value to check, and pydicom has chosen any VR in doubt itself and read a UN sequence’s items unchecked, so such an element cannot be decoded either. Specific Character Set (0008,0005), whichdcmreaddecodes itself, and a sequence of undefined length, which it reads as items, are the exceptions. Building the first pass’s records decodes elements in this way, so the second pass reads each file again rather than reuse those data sets. What happens to an instance with an element that cannot be decoded depends on that element’s rule. As the maintainer decided on 1 October 2026, text with bytes outside the Default Character Repertoire where no Specific Character Set applies sequesters its instance only where the text would be kept or cleaned; where its rule removes or replaces it, the instance is de-identified. As the maintainer clarified on 2 October 2026, that transformation proceeds, but whether the output may be released depends on the coverage of the residual search (D-010, D-027). Decoding, reading the first pass’s records, adding the de-identification markers, and writing output redact pydicom’s warnings and log records, including those of loggers belowpydicomand debug records, with the engine’s ownredacted_diagnostics, only in the thread that calls pydicom and only while it does, and without adding to Python’s process-wide warning filters. Attributes absent from the pinned dictionary and without an L2 rule are removed. Retired attributes follow Table E.1-1 where listed and L2 otherwise.As the maintainer decided on 1 October 2026, the engine admits sources strictly, decodes selectively, and verifies what it preserves (B+); it is not a general DICOM normaliser. A source file is admitted only once its whole structure is read from its own bytes, independently of pydicom: the preamble, the File Meta Information, every element’s header and length, rising tags in each data set and item, so that no tag repeats, each item and delimiter, a bound on nesting, and Data Set Trailing Padding, with nothing after the last element, in Implicit or Explicit VR Little Endian, or in a transfer syntax that encapsulates Pixel Data in an Explicit VR Little Endian data set and that pydicom 3.0.2 can decode: JPEG, JPEG-LS, JPEG 2000 Part 1, HTJ2K, or RLE Lossless (PS3.5 Section A.4). Which of them a release de-identifies is for its scope to decide, and the first supported release de-identifies instances in each of them (D-010); one that is sequestered is still read, so that its values reach its subject’s residual search (D-027). Before one that it de-identifies is written, every frame of its Pixel Data is decoded once, one frame at a time, by the pydicom decoding plugin pinned to its transfer syntax, whatever else is installed: GDCM, through python-gdcm, for JPEG and JPEG-LS, pylibjpeg, with pylibjpeg-openjpeg, for JPEG 2000 and HTJ2K, and pydicom’s own for RLE Lossless, but imagecodecs for the frames that pydicom 3.0.2’s GDCM plugin refuses (D-055). GDCM, pylibjpeg, and imagecodecs decode in one child process, kept for the life of the process that runs the engine, since a malformed codestream can make a native library end the process that calls it, which no exception handler can prevent: GDCM 3.2 aborts whenever libjpeg warns while reading a JPEG frame’s header, other than that it must scale the image down, as for a JFIF segment of a version other than 1. A frame whose decoder ends the child is
undecodable-pixel-data, or, in the comparison of a written frame with its source’s,cut-changed-pixels, and the next decode starts a new child. Where the child cannot be started, the instance isno-decoder, and the engine logs a warning saying so, once per process. A decode refused because the engine’s process is exiting, as one in a daemon thread, isno-decoder, orcut-changed-pixelsin the comparison, with no warning. The engine reads what the child sends back as JSON of a checked form, never as a pickle, so that a decoder that a codestream subverts cannot, through what it sends back, make the engine’s process run code, import a module, or change its objects. The child is treated as possibly compromised: it is sent only plain data, a frame’s codestream and the attributes that describe the frame, and the engine never imports, calls, or looks up an attribute by a name that it sends back. Under the Clean Pixel Data Option, its decoded samples become the written Pixel Data of every instance that it cleans (D-037), so they are checked against the frame’s attributes, the instance is held for review, whose previews show each frame as written, which is the child’s decode, and, beside each frame with a region, the same decode as received, written uncompressed for the QC pack so that the engine’s process never decodes the codestream to show it, and a verdict releases it only where its frames decode to the same SHA-256 again (D-048); a subverted decoder can still send samples of the expected form that are not its codestream’s, which only that review can catch. The QC pack’s previews of other files still decode in process, since they decode only released or held files, whose frames this check has already decoded with the same plugin, but for frames that imagecodecs decodes, which are decoded for their previews in the child too (D-055). As the maintainer decided on 7 October 2026, each is licensed at least as permissively as PyMedPhys’s Apache License 2.0, so pylibjpeg-libjpeg, under the GNU General Public License version 3, is not used. pydicom 3.0.2’s GDCM plugin refuses three kinds of frame before GDCM sees them, JPEG Extended at a precision of 12 bits, JPEG-LS at 6 or 7 bits, and signed JPEG-LS Near-Lossless below 8 bits, so those are decoded with imagecodecs, through libjpeg-turbo and CharLS, each also licensed at least as permissively (D-055). A Basic Offset Table that is not empty must give one offset for each frame, from 0 and rising, each where a fragment’s Item Tag starts; an Extended Offset Table (7FE0,0001) must come with Extended Offset Table Lengths (7FE0,0002) and an empty Basic Offset Table and give each fragment in turn; and the frames must decode and match Number of Frames, or one where it is absent, but never for a value of zero or an empty one, Rows, Columns, and Samples per Pixel. Since a decoder shapes a frame by those attributes, each frame’s codestream header is also read before decoding, the JPEG or JPEG-LS frame header or the JPEG 2000 or HTJ2K SIZ marker segment, and must give the same Rows, Columns, and Samples per Pixel, a sample precision equal to Bits Stored, and, for JPEG 2000 and HTJ2K, no subsampled component, signedness as Pixel Representation gives it, and a multiple component transformation as Photometric Interpretation gives it (PS3.5 Sections 8.2.1, 8.2.3, 8.2.4, and 8.2.14). The codestream must also be of the coding process that its transfer syntax names (PS3.5 Section A.4): the JPEG frame header SOF0 for JPEG Baseline, SOF0 or SOF1 for JPEG Extended, and SOF3 with every scan’s point transform 0 for JPEG Lossless; every scan lossless, with NEAR and the point transform 0, for JPEG-LS Lossless; and only the reversible wavelet, in the main header and every tile-part header, for the JPEG 2000 and HTJ2K syntaxes that are lossless only. The reversible wavelet is needed for lossless coding but does not show it: a codestream that uses it can be truncated, a lossy process (PS3.5 Section A.4.4), and whether every coding pass was kept is recorded only in packet headers. As the maintainer decided on 7 October 2026, for those syntaxes every packet header of every tile is therefore read too, in its progression order, and each code-block that the packets include must hold every coding pass to its least significant bit-plane:3 (M_b - P) - 2passes for ITU-T T.800 coding, and an HT cleanup pass to bit-plane 0, alone or with both refinement passes from bit-plane 1, for ITU-T T.814 coding. A frame that lacks a pass isframe-mismatch; one whose packets do not hold together, or that uses packed packet headers, progression order changes, a region of interest, Part 2 extensions, mixed HT code-blocks, or an HT code-block in more than one packet, isundecodable-pixel-data. A code-block that no packet includes is decoded as all zero, so a codestream truncated so far that it drops only whole code-blocks is not detected. A JPEG or JPEG-LS codestream must reach its EOI marker, and each scan must hold entropy-coded data, since GDCM decodes a frame whose scan is empty, or that lacks only its EOI, without an error, and pylibjpeg also one cut short within its scan; damaged entropy-coded data still followed by EOI is not detected. Otherwise the instance is sequestered, asno-decoderwhere the plugin is not installed or cannot be run,offset-table-mismatch,undecodable-pixel-data, orframe-mismatch, so compressed pixel data are never released unread. Theuserextra declares the plugins; thedicomextra does not, so with it alone only RLE Lossless can be decoded. Every Value Length and Item Length but the undefined length must be even (PS3.5 Sections 7.1.1 and 7.5), in the File Meta Information and at every depth of the data set, although the layout reader used to search written files for residual values reads odd lengths, so that nothing in such a file escapes the search. The engine keeps an immutable copy of those bytes as the source evidence, with where each element’s Value Field is and its VR as written; a pydicom data set is only a mutable view of it, read afresh when needed. An element read for a decision is decoded from the evidence’s Value Field, so pydicom decoding it on access changes neither the evidence nor what the engine reads. An element still encoded whose bytes or VR differ from the evidence, an element set in memory, and a decoded sequence whose items differ in number from the source’s cannot be read as source. An element that pydicom has already decoded is read from the evidence whatever value the view now holds, since pydicom keeps no encoded form to compare, so the view is never the authority on a source value. Source text is decoded in the character set that the source declares, whatever the view’s Specific Character Set now holds. Everything else is refused with a reason code and the offset where reading stopped, never a value.The engine verifies what it preserves from the bytes of each written file’s data set, including Data Set Trailing Padding, read as a source is, against the plan for its instance: which elements, by path, were kept, which emptied, replaced, or introduced, and which removed, with everything inside a removed sequence. Paths number items as the source does. Where Clean Structured Content removes an item of Content Sequence on its own (D-047), the plan lists it, the writer leaves it out, and each element of the items after it is verified where the output holds it, one place earlier for each removed item before it in the same sequence. The preamble and File Meta Information are replaced (D-025) and not compared. An unchanged transfer syntax is necessary but not sufficient. The written file must have its source’s transfer syntax, since the first supported release does not transcode, except that compressed Pixel Data that the Clean Pixel Data Option cleans is written uncompressed, in Explicit VR Little Endian, as a replaced value (D-037); every source element must be planned once; nothing outside the plan may be written; every kept element must be in both files; and every emptied, replaced, or introduced element must be written. A kept element must have the VR as written in its source, which is absent in implicit VR, and, unless it holds items, the same header length and length form and the same Value Field, byte for byte; a kept sequence must have as many items, and its items’ elements are verified by their own paths, so its length may be defined in one file and undefined in the other. A kept private element, including a private sequence or a private UN that holds items, must have a Private Creator with the same bytes in its own data set, or none in either file. Kept text of SH, LO, ST, LT, UT, UC, or PN, or of a VR not known, must also be in a Specific Character Set with the same bytes, that of its own data set or of the nearest item or data set that holds it and has one (PS3.5 Section 7.5.3); an empty one counts as absent, since both give the Default Character Repertoire. Nothing is decoded to compare: two encodings that decode to the same value, such as
1and01in an IS, differ. Encapsulated Pixel Data of the top-level data set, of VR OB and starting with its Basic Offset Table item, in a transfer syntax that encapsulates it, has no single Value Field, so it is copied and compared whole, byte for byte: its Basic Offset Table, every fragment with its item header, and its delimiter. Any other kept value of undefined length without items, such as fragments elsewhere, cannot be verified. Each failure names a reason and an element path, never a value, and its instance is to be sequestered. Emptied, replaced, and introduced values are validated before they are written.The engine therefore writes each data set from its source evidence rather than through pydicom’s data set writer, which resolves an ambiguous VR, such as US or SS, from the data set it writes wherever it holds the VR as ambiguous, as for an element read from implicit VR or from the items of a UN sequence. Once a data set has been walked, pydicom writes a VOI LUT Sequence (0028,3010) that the source holds as UN as SQ, with the LUT Descriptor (0028,3002) of a CT image in Hounsfield Units as US rather than SS, which verification refuses. The engine’s writer copies each kept element, header and value, from the source’s bytes, including a sequence or other element holding items when nothing in it changes, so that an opaque value of defined length that happens to read as items is never rewritten as a sequence; it leaves out each removed element with everything in it. It writes each kept sequence with a change in it with its tag and VR as written and an undefined length, and each of its items with an undefined length, ended by the Item and Sequence Delimitation Items (PS3.5 Sections 6.2.2, 7.5.1, and 7.5.2), so that no length is worked out again when an element in an item changes; every item is written, even one whose elements are all removed. Only replacements and introduced elements are encoded, each by pydicom’s writer for one element, with the VR it is given and the Specific Character Set in force at its place in the output, and placed in ascending order of tag; an introduced sequence’s items are encoded in the same way, from their elements as held, without pydicom resolving any VR. A replacement is refused if it is still encoded, has an ambiguous VR, is a File Meta, command, or group length element or a delimiter, would be written with another VR, as pydicom writes UN for a value too long for its VR, or has text that cannot be written in the character set in force, which must be one the element decoder accepts (item 5), or, for a VR of the Default Character Repertoire alone, outside ISO 646. A plan is refused where it keeps an element inside one that is removed or replaced, keeps a group length, which could go stale, or changes the character set in force over kept text. A kept sequence stored as UN stays UN, with its items in implicit VR (PS3.5 Section 6.2.2), even where an element in them changes: its kept elements stay byte for byte as the source has them, and a reader resolves each VR in its items from its dictionary, as it does for the source. Rewriting it as SQ with explicit VR items would give every kept element in it a new header, and needs a VR for each, which a private attribute may not have. Where no VR is written, in implicit VR or in such items, a replacement is refused unless the pinned dictionary gives its VR alone, since an ambiguous VR such as US or SS, or another VR, could be read otherwise. Encapsulated Pixel Data of the top-level data set is copied byte for byte, or, where item 7 cuts metadata from its codestreams, written anew with VR OB, an undefined length, its items, each of an even, defined length, and the Sequence Delimitation Item; any other kept value of fragments is refused, since verification could not show it preserved. The File Meta Information and preamble come from D-025.
An attribute of the pinned dictionary that no rule covers, and that the engine does not itself remove or write (D-012, D-013), is kept if its VR is CS, AT, or a numeric VR, and a sequence or a binary value is kept only where the IOD defines the attribute at that place, with the attributes in a kept sequence’s items handled by the same rules. Such an attribute of any other VR is removed (D-022).
Content that cannot be decoded inside a sequence that is removed is removed with it, and its values are listed as not collected in the confidential QC material, which makes the collection for the residual search incomplete (D-027). An instance is sequestered only where content that cannot be decoded would be kept or cleaned.
Each data set is planned before any of its values is read, from the source evidence’s structure alone: each element’s rule and action at its place, with compound actions resolved by Type, and what must read its value. The readers are UID replacement, the comparison of a dummy value with the source’s, cleaning, and residual collection, which takes every value that is removed or replaced, those of a removed sequence’s descendants included, whatever its VR, leaving what is searched to the residual search’s own rules (D-027). A sequence is descended only under K or U, and its items’ elements take their own rules; under any other action, its descendants go with it and take no rule of their own. The plan sequesters the instance where a dummy value is to be written but neither the VR nor a reviewed rule gives one (D-021), and where an attribute that is not removed is written with a VR, other than UN, that the pinned dictionary does not give it. Only the values that a reader needs are then decoded.
Compound actions such as X/Z/D are resolved from the strictest Type that the IOD gives the attribute at its place in the data set, as are plain actions where the IOD requires the attribute there or does not define it there (D-020). Z and D write the values that D-021 sets.
L3 rules are validated as D-011 requires.
Each element takes the rule of the first of these that covers it: the engine’s own removals, of groups 0000, 0002, and 0004 within a data set, group lengths (gggg,0000), and Data Set Trailing Padding (item 7, D-016, D-025), and of Encrypted Attributes Sequence (D-013); Table E.1-1’s Private Attributes row, for an odd group other than 0001, 0003, 0005, 0007, and FFFF, which PS3.5 Section 7.8.1 does not allow for private use; the table’s other rows, by exact tag and then by masked tag, where (50xx,eeee) and (60xx,eeee) match only the repeating groups 5000 to 501E and 6000 to 601E (PS3.5 Section 7.6); the L2 rules; U by the role of a UI attribute (D-003); removal by Type of a text attribute (D-022); the rule for attributes that no rule covers (D-022); and, for an attribute absent from the pinned dictionary, removal. A sequence to which the policy gives C takes its Basic Profile action (D-009). A test fails if a person name, date, time, datetime, or UI attribute of the pinned dictionary reaches the rule for attributes that no rule covers.
Identifiers. Keyed replacement of UIDs (D-003) and patient identifiers (D-005), using keys and subject profiles held by a custodian (D-004). Under Retain Device Identity, the AE titles that Table E.1-1 gives C become keyed tokens, by the first of the reviewed cleaners that settle C (D-034).
Dates and times. Per-subject shifts (D-006), handling of each temporal attribute by its role (D-007), and stable synthetic birth dates for
tps-import(D-008).Free text. Descriptor cleaning (D-009) and the reviewed rules for text attributes that Table E.1-1 omits (D-022). Text is decoded according to the Specific Character Set (0008,0005) of its data set, or of the sequence item that has its own (PS3.5 Section 7.5.3), before matching, cleaning, or hashing. A data set whose Specific Character Set is not supported or is invalid is read in the Default Character Repertoire, as one without a value is, and an instance whose Specific Character Set cannot be read is sequestered (D-010). Specific Character Set is supported only as the Defined Terms of PS3.3 Section C.12.1.1.2 that pydicom can decode, combined as that section and PS3.5 Section 6.1.2.4 allow; in 2026d this leaves out ISO_IR 203 and ISO 2022 IR 203. ISO_IR 6 is also accepted alone: that section gives the Default Character Repertoire by the absence of a value, not by ISO_IR 6, but real data commonly holds ISO_IR 6, which names the same repertoire, so it is read as an absent value is, and decoded just as strictly. With other values it is not supported, since ISO 2022 IR 6 is the Defined Term for that repertoire with code extensions. Text that does not decode exactly in its character set cannot be decoded; where the Default Character Repertoire is the only character set, that includes any character outside ISO 646 (PS3.5 Section 6.1.2.1), although pydicom reads that repertoire as ISO 8859-1, and item 2 sets out when such text sequesters its instance. Nor is reading more lenient than writing: text that D-011’s check of a written value finds could not be written back in its character set cannot be decoded either, such as a kanji in Shift JIS where Specific Character Set is ISO_IR 13, which is single-byte. That check encodes each whole value as pydicom’s writer does, with the codec it chooses, and reads it back: a value that does not read back as the same single value, such as Latin letters and katakana together in ISO_IR 13, which pydicom writes with replacement characters, or a yen sign there, which JIS X 0201 places at the backslash that separates values (PS3.5 Section 6.1.2.3), cannot be written. Replacement values are encoded in the dataset’s character set, and the dataset is converted to UTF-8 (ISO_IR 192) when a value cannot otherwise be encoded. The residual search (item 8) encodes each decoded source value again, in its source character set, UTF-8, ISO 8859-1, and UTF-16LE. Text with bytes outside the Default Character Repertoire that no Specific Character Set applies to is read for the search as ISO 8859-1, in which every byte is a character, so encoding it again in ISO 8859-1 gives its own bytes, and a copy of it left in the output is still found. That byte search supplements the coverage but does not stand in for the decoded text, whose copies in other character sets are not searched, so the value counts as read only as bytes and its collection as incomplete (D-027).
Private attributes. Removed unless the Retain Safe Private Option is selected.
Without that option, every element of an odd group is removed, at the top level and in the items of every standard sequence, and a private sequence is removed with everything in it (D-028).
With that option, a private attribute is retained only when shown to be safe by a route E.3.10 allows. It is matched by private creator, whichever block it occupies (MIDI §1.17.3), and the conformance statement lists each rule that can retain one, with its basis (D-035).
The L2 file
safe_private.tomlholds the reviewed rules: one for every row of Table E.3.10-1, and for each reviewed addition with its public source, each giving how a retained value is handled (D-035).TCIA’s Private Tag Dictionary ships unchanged in
_tcia/, pinned by its SHA-256, as a second list that a run may choose instead of the reviewed rules; the method digest, the release report, and the conformance statement record which list a run used (D-035).Table E.1-1 gives retained private attributes C, which each rule’s handling settles: numbers and code strings are checked and kept, UIDs are replaced by D-003, and text is cleaned as descriptors are under Clean Descriptors and removed otherwise (D-009, D-035).
An instance’s own Private Data Element Characteristics Sequence (0008,0300) is also a route: an attribute in a block that it marks SAFE in Block Identifying Information Status (0008,0303), or that it lists in Nonidentifying Private Elements (0008,0304), and that no rule lists, takes the handling of its VR, and one that it says may identify is removed, even where a rule would keep it (D-035).
Every other private attribute is removed, which E.3.10 allows in place of processing it as Deidentification Action (0008,0307) recommends, and (0008,0300) itself is removed by its supplementary rule (D-035).
A private sequence is parsed, and each nested attribute is handled on its own merits, as E.3.10 requires. One that no rule lists is kept, with its private creator, only where something in its items is kept or replaced (D-035).
File container.
The engine replaces the File Meta Information and the preamble, as E.1.1 requires: it builds the File Meta Information itself, describing the de-identifying application as D-025 sets, and writes a zeroed preamble (D-002).
It removes group 0004 from every file other than a DICOMDIR, and removes Data Set Trailing Padding. It also removes every element of group 0000, the DIMSE command set (PS3.7 Section 6.3), wherever it appears in a data set, as the maintainer decided on 1 October 2026: a command element has no place in a stored instance, and one such as Requested SOP Instance UID (0000,1001) would otherwise carry a source UID that no UID role replaces. A source DICOMDIR is never passed through, and none is written, since the output is a plain directory tree rather than a File-set (D-016); E.1.1 would allow one only if regenerated from the de-identified files.
Encapsulated Document (0042,0011), which Table E.1-1 gives D under every option, is replaced, or the instance is sequestered, where the IOD defines it at that place. Of the IODs of the first supported release, only Encapsulated PDF defines it, as Type 1, and no reviewed rule gives a document a dummy value, so every Encapsulated PDF that holds one is sequestered, with that attribute and D as its reason, and nothing of it is written (D-010). Elsewhere it is removed, since D acts as X on an attribute that the IOD does not define at that place (D-020).
Metadata in compressed pixel data bitstreams, such as JPEG APPn segments, is removed without recompression. Each frame’s codestream of encapsulated Pixel Data is parsed, and every byte of it accounted for: the frame is found from the Basic Offset Table, as one fragment, or by parsing the fragments one codestream after another, each ending where a fragment ends. Every comment (COM) and application (APPn) marker segment of JPEG and JPEG-LS is cut, except a JFIF APP0 without a thumbnail, an Adobe APP14, and, in JPEG-LS, an APP8 colour transform, each of fixed format, which say how to decode colour and are kept once parsed; so is every comment (COM) in the main header of a JPEG 2000 or HTJ2K codestream. An RLE Lossless frame has no metadata segments; its header and segments are parsed, and each segment must decode to one byte plane. A frame that cannot be found or parsed, a marker that its transfer syntax does not define, a JPEG 2000 codestream inside a JP2 file, and any byte after a codestream’s end other than one padding byte of 0x00 sequester the instance (
unparsable-codestream), since bytes that no decoder reads could carry anything; so do a comment in a JPEG 2000 tile-part header, which could be cut only by rewriting the tile-part’s length, and a cut where an Extended Offset Table is present, whose values would have to change too (uncuttable-metadata). Where something is cut, Pixel Data is written anew, one fragment for each frame, with a Basic Offset Table where the source had one, and every frame of the written file must decode to the same pixels as its source’s frame, by the same pinned plugin (item 2), or the instance is sequestered (cut-changed-pixels). Pixel Data that the Clean Pixel Data Option writes uncompressed holds no codestream, so nothing is cut from it (D-037). Where nothing is cut, Pixel Data is kept byte for byte.A run lists every entry below its source directory, in an order that depends only on their paths relative to it, and names each input by its position in that order, its run position. It follows no symbolic link or other link, opens no file that is not a regular file, and reads a file only while it is still the one that it listed.
Output file and directory names are built only from replacement identifiers, never from source paths, file names, or attribute values. Each instance is written to
<Patient ID>/<Study Instance UID>/<Series Instance UID>/<SOP Instance UID>.dcmbelow the output directory, from its replacement values, or from the keyed replacements of the UIDs that the Retain UIDs Option keeps (D-016, D-040).De-identification markers follow D-012.
Referential integrity.
A first pass builds a graph of instances and references. It reports dangling references, frame of reference mismatches, and inconsistent hierarchy using opaque identifiers, before anything is written. It follows the reference attributes that the PS3.3 tables define inside a sequence of the instance’s IOD, and resolves each against the inputs’ SOP Instance, Series Instance, or Study Instance UIDs, by the level of what it names. The attribute gives the level, except that Referenced SOP Instance UID names a study in the items of Referenced Study Sequence and RT Referenced Study Sequence, whose Referenced SOP Class UID is the study’s own class, such as the retired Detached Study Management (PS3.3 10.6.1 and C.8.8.5.4). An empty value where the IOD makes the attribute Type 3 means the same as an absent one (PS3.5 7.4.5), so it is no reference; an empty Type 1 value is invalid and an empty Type 2 value is unknown (PS3.5 7.4.1 and 7.4.3), so each names nothing, and is dangling unless the class rule below applies. Where the IOD’s definitions give an attribute several Types at one place, the strictest applies, with 1C as 1 and 2C as 2. A reference to an instance whose Referenced SOP Class UID is not a Standard Storage SOP Class of PS3.4 Table B.5-1, such as a Private or retired SOP Class, resolves if it names an input; otherwise it is not reported, because such a class may name something that is not a stored instance, such as a performed procedure step, or a patient through a retired or private management class. The class rule does not apply to a reference to a study, which is dangling unless an input has that Study Instance UID. A UID that the pinned tables register is never dangling. Findings name inputs by their position in the run and attributes by their tags, and contain no values.
The first pass also reports an inconsistent hierarchy: instances that share a SOP Instance UID, as identical duplicates where their source bytes are the same and as conflicting copies otherwise; a series whose instances name several Study Instance UIDs; and a study whose instances name several patients, each the identity of a Patient ID with its issuer (D-005). The instances without a Patient ID together count as one more patient, apart from every identity (D-026), and an instance without the UID that a check compares is left out of that check, since it is already reported as missing that identifier. The first pass also reports a frame of reference mismatch: a series whose instances name several Frame of Reference UIDs (0020,0052), though “each Series shall have a single Frame of Reference UID” (PS3.3 C.7.4.1.1.1); an RT Structure Set ROI whose Referenced Frame of Reference UID (3006,0024) has no value or is not listed “once and only once” in the structure set’s Referenced Frame of Reference Sequence (3006,0010) (PS3.3 C.8.8.5.1); and an input image that an item of that sequence lists in its Contour Image Sequences under a frame of reference other than the image’s own, since the frame of reference of a set of ROIs is “obtained from the source images” (PS3.3 C.8.8.5.1, Note). An input or item without a Frame of Reference UID is left out of the comparisons it would take part in. A run reports each such mismatch only, as it does a dangling reference (D-026). An instance’s source bytes are its Transfer Syntax UID (0002,0010) and the bytes of its data set from the end of the File Meta Information to the end of the file, leaving out each group length (gggg,0000), which PS3.5 7.2 retires, and the Data Set Trailing Padding (FFFC,FFFC) at the top level of the data set; the preamble and the File Meta Information are not part of the data set (PS3.10 7.1). A group length or padding inside an item is compared as it is. Copies are identical only when their source bytes are the same (D-026). The first pass finds the bytes with PyMedPhys’s own reader of a file’s structure, which decodes no value, so no decoder or guessed VR takes part in the comparison. Copies that differ only in their encoding therefore conflict, which sequesters them: copies in Implicit VR and in Explicit VR Little Endian, with sequences or items of defined and of undefined length, with values padded differently, or with compressed and uncompressed Pixel Data. A copy whose bytes cannot be shown to be sound conflicts with every other copy: one whose structure cannot be read to the end of the file, one without a Transfer Syntax UID, one whose transfer syntax deflates the data set or is the retired Explicit VR Big Endian, and one with a top-level group length or Data Set Trailing Padding that holds items, whose elements would otherwise be compared as if they were at the top level. A file in which a sequence that the first pass follows does not hold only items, including any such sequence in Explicit VR Big Endian, which only pydicom can read, has no record, since its references cannot be followed; the first pass refuses it by the sequence’s path. The first pass reads each file in full, and compares SHA-256 digests of the source bytes, which it keeps only for the run.
After writing, the engine verifies one-to-one UID mappings; consistent references; consistent values for each entity above the instance level, such as Patient ID, Study ID, and Series Number (E.1.1 step 2, Note 3); absence of original UIDs where replacement or removal is required; and unchanged values where retention is required. A run checks the UIDs and references of the files that its gate releases against the first pass before it publishes anything. A finding there is a fault of the engine, so the run sequesters each instance that it names and checks the rest again; a reference to an instance that was withheld is reported only, as a dangling reference is (D-026); and a check that fails, or a finding that no sequestration isolates, publishes nothing.
It searches every byte of each written file for the source values that had to be removed or replaced: the instance’s own, and its subject’s from the run’s other instances. It reports each residual, a source value found in a form the search derives, by the value’s kind (person name, UID, date, datetime, or other text), its source attribute path, the form and encoding found, and its place: the preamble, a File Meta Information element, a data set element by its path, with sequence items numbered from 0, Data Set Trailing Padding, or the bytes after the last readable element. It also lists each form it did not search, and why. Neither list contains a source value (D-016). The search itself decides nothing: output is written to a staging area, and the release gate (
pymedphys._dicom.deidentify.release_gate) runs the search of each written file itself, for exactly the values collected across the file’s subject, and decides from the search and the coverage of that collection whether the file is released, goes to QC review, or is withheld, with the consequences that D-027 sets. A search that finds nothing is not on its own a release.Forms. Each value is searched as given, composed (NFC), decomposed (NFD), with compatibility characters replaced (NFKC and NFKD), and with each character that has a half-width or full-width form written in its other width, such as
ヤマダforヤマダorYAMADAforYAMADA. It is split at backslashes unless its VR is LT, ST, UR, or UT, and stripped of spaces, NULs, and whitespace at either end. A person name is searched whole, by each component group, by its family, given, and middle names, by each word of those names between spaces or hyphens, and with its family and given names run together in either order, as Chinese, Japanese, and Korean names are usually written. Where the family or given name has fewer than four characters, they are also searched in either order with a space or an ideographic space (U+3000) between them, and as “family, given”. A name with an apostrophe, whether ASCII’s or U+2018, U+2019, or U+02BC, is also searched with ASCII’s, with U+2019, and without it. A date, including one written as YYYY.MM.DD, as ACR-NEMA wrote dates, is also searched as YYYYMMDD, YYYY-MM-DD, YYYY:MM:DD (as EXIF writes dates in bitstream metadata), DD/MM/YYYY, MM/DD/YYYY, and DD.MM.YYYY, and a datetime by its date in each of these. A UID or other text is searched as it is, by up to its first 256 characters.Not searched. Forms of fewer than four characters, counted once composed (NFKC); binary values; values that cannot be decoded, which are removed with the sequence that contains them (item 2), apart from text with bytes outside the Default Character Repertoire that no Specific Character Set applies to, which is read as ISO 8859-1 (item 5); datetimes without a full date, such as
2024, which would match any number that contains it; and values of VR AS, AT, CS, DS, FD, FL, IS, SL, SS, SV, TM, UL, US, and UV, whose codes, numbers, ages, times, and tags occur throughout files and are checked attribute by attribute instead. Each is listed as not searched (D-027).Not collected. As the maintainer clarified on 2 October 2026, a value that cannot be decoded is never collected, so it is also listed as not collected, as text read only as ISO 8859-1 (item 5) is listed as read as bytes, and both make the collection incomplete (D-027).
Constants. A value that equals a constant the engine writes whatever the source held is not searched, since finding it would reveal nothing about the source. The constants are D’s constants and second constants of the VRs that are searched, the values of the item that D writes in Person Identification Code Sequence (D-021), and the markers’ fixed values: Patient Identity Removed, Longitudinal Temporal Information Modified, Manufacturer, and the Code Value, Coding Scheme Designator, and Code Meaning of each code that the markers can write (D-012). Keyed values, such as replacement UIDs and pseudonyms, and the markers’ versions and method digest are not constants. A value is compared with each constant as D compares a source value with its constant, as text of the source value’s VR (D-021), so that
Deidentifiedand1900.01.01are skipped; a value of several values is compared value by value, and only those equal to a constant are skipped. Each form that the search derives from a value, such as a person name’s family name or a datetime’s date, is compared in the same way, and a form equal to a constant is skipped while the value’s other forms are still searched. Each source attribute skipped in whole or in part is recorded once by its attribute, never by its value (D-027). A value of a VR that is never searched is listed as not searched for that reason instead.Encodings and case. Each form is searched in UTF-8, ISO 8859-1, UTF-16LE, and its source character set (item 5). In the source character set, a form can also be spelt with ISO 2022 escape sequences, whose bytes depend on the text around them: where the character set’s codec writes them itself, or, for a form that is not ASCII, where Specific Character Set has more than one value, so that a writer puts one before each component in another character set (PS3.5 Section 6.1.2.5.3). Such a form is still searched as the codec encodes it, which finds a single component after its escape sequence, or text written without them, as pydicom writes ISO 2022 IR 58 text; it is also listed, since its spellings with other escape sequences are not searched. Where the codec designates a character set before the form and resets after it, as ISO 2022 JP does, the bytes between them are also searched, as a longer run in that character set, such as the form followed by an honorific, writes them. ASCII letters match in either case, and text with other letters is also searched in upper, lower, and title case; a capital inside a word on a letter outside ASCII, as in a McDonald-style spelling in Cyrillic, is found only where the whole form is in one of those cases. Case is folded byte by byte, so a byte of an ASCII capital inside a character of several bytes, as in UTF-16LE, Shift_JIS, or GBK, is folded too, and some text outside ASCII matches a form by chance; this errs towards a finding.
Matches. Letters and digits are those of ASCII, and in UTF-16LE each neighbouring character is two bytes. A match does not count where a digit precedes a form that starts with a digit, as in a 39-digit component of a
2.25.UID; where a digit follows a form that ends with one, unless the form is a date or datetime, which a time may follow, or the first 256 characters of a longer value; where a letter adjoins a person name form at an edge that is a letter, as “MARY” in “PRIMARY”; for a form of digits alone, inside a DS or IS value, such as contour data; or, for a form of digits alone that a digit follows, inside the integer of a UI value under the2.25.root (PS3.5 B.2), which the engine uses for keyed replacement UIDs, so that a date at the start of a keyed replacement UID is not a finding. That rule recognises the root, not who wrote the UID, so it applies to a source UID kept under that root too, and should be reassessed before a preset keeps source UIDs; digits that make up the whole integer, and UIDs under other roots, are still found. These rules are for text: a match wholly in a value that holds numbers, below, or in the fragments of encapsulated Pixel Data whose codestreams all parse counts whatever bytes adjoin it, since they are samples and coding parameters, not letters or digits of a longer word or number.Values that hold numbers. Native Pixel Data, Float Pixel Data, and Double Float Pixel Data of the top-level data set, and values of VR OD, OF, OL, OV, and OW, are searched only for forms of at least 8 bytes that are not UTF-16LE, since UTF-16LE text and shorter forms match sample values by chance. The entropy-coded data of encapsulated Pixel Data of the top-level data set, with its Basic Offset Table, where every codestream of its fragments parses, are searched only for forms of at least 6 bytes that are not UTF-16LE, except in RLE Lossless, below: compressed samples match short forms by chance as often as random bytes do, or more. Measured on 7 October 2026 over synthetic phantoms of 12 bits, 256 by 256, in JPEG Lossless, JPEG 2000 Lossless, RLE Lossless, and JPEG Baseline, each 4-letter form matched by chance about once in every 30 to 200 MB, and each 4-digit form up to once in every 40 MB, against about once in every 40 TB or more for an 8-letter form. A run of a few GB with tens of short forms would therefore hold hundreds of files for review for nothing. Text in a codestream lies in its marker segments, which item 7 cuts or parses. Its entropy-coded data hold samples as native Pixel Data does, but also bytes that no decoder reads: after the data a decoder needs, at the end of a JPEG or JPEG-LS scan or restart interval, of a JPEG 2000 tile-part, or of a JPEG 2000 code-block’s codeword segments, a writer can put anything, and the frame still decodes identically. Finding those bytes would take a full decode in JPEG 2000, so, as the maintainer decided on 10 October 2026, the entropy-coded data are searched for forms of 6 bytes or more, not 8 as sample values are, and names and other forms of 4 and 5 bytes there are not found. RLE Lossless has no such bytes, since item 7 parses each of its segments, which must decode to exactly one byte plane, so its fragments are searched as values that hold numbers. Searching them for forms of 6 bytes would find nothing hidden and would cost more than elsewhere, since RLE keeps each byte of the samples in its own segment: the low bytes of soft tissue in CT, such as stored values 1072 to 1081 (48 to 57 HU with a rescale intercept of -1024), are the ASCII digits, so a numeric identifier of 6 digits matches by chance far more often than a 6-letter form. Estimated on 10 October 2026 from the runs of letters in the entropy-coded data of synthetic CT phantoms, 512 by 512, each 6-letter form would match by chance about once in every 0.2 TB in JPEG Baseline and once in every 1 to 6 TB in JPEG 2000 Lossless, JPEG 2000 at 10:1, and JPEG Lossless SV1; searching 1.5 GB of those phantoms, 300 MB in each, for a patient’s invented values, of whose forms 6 are of 6 or 7 bytes, found nothing. Every other byte, including the marker segments of those codestreams, fragments whose codestreams do not parse, OB and UN values, and bytes that cannot be read as elements, is searched for every form.
Reports. Each source attribute is reported once for each place it is found, by its widest form there, with the encoding and byte offset of that form’s first match there. A file whose structure cannot be read to its end is still searched in full, and reported as not fully readable.
It reads each written file’s structure independently of the library that wrote it, so that anything verification finds is located by element path, or in the preamble, the File Meta Information, Data Set Trailing Padding, or the bytes after the last readable element.
The first pass’s findings have graded consequences, from reporting a dangling reference to stopping the run for a study with several patients, or, where a run is told to, sequestering that study (D-026).
Risk detection and quality control. Indicators for burned-in text and reconstructable faces (D-015), a restricted QC pack for human review (D-016), and statistical disclosure control (D-017).
A text detector,
pymedphys._dicom.deidentify.text_detection, proposes boxes around burned-in text for the Clean Pixel Data Option (E.3.1), whose regions the engine blacks out (D-037). It runs PaddleOCR’s PP-OCRv6 small text detection model, licensed under Apache-2.0, which it downloads on first use from RapidOCR’s wheel on PyPI, pinned with the model by SHA-256, on ONNX Runtime from thetext-detectionextra, single-threaded, with ONNX Runtime’s telemetry disabled before it is imported; on Windows it runs only the officialonnxruntimewheel from 1.31, the first whose telemetry that setting turns off there. It searches each frame’s full stored range and its white and black top-hats, and drops regions too wide or too sparse to be lines of text, which the network otherwise marks on smooth anatomy. It reads no text and can miss faint or small text, so it guides review rather than replacing it.
Reports.
Each run writes a machine-readable and human-readable release report, which contains no source values or original paths (D-016) and names released instances only by their output names and sequestered instances only by labels (D-026). It records the method digest with its components (D-024) and the runtime environment that ran (D-029). Its human-readable form,
release-report.mdbesiderelease-report.json, is CommonMark, with GitHub Flavored Markdown tables, generated from the JSON text alone, which shows each of its values as a code span and draws nothing else from it, so it can hold no value or path that the JSON lacks. Its machine-readable form is a JSON document labelled with its format,pymedphys-deid-release-report/68, whosepolicysection names the PS3.15 edition, the preset (none for a custom option set), the selected options, and whether the policy can claim conformance, and whosemethodandruntimesections hold the fields that D-024 and D-029 list. Itskeysection gives the scope of the run’s key,runorproject, and for a project key its non-secret identifier, and for a run-scoped key none (D-004). Itsqc_reviewsection gives the run’s QC pack by its opaque reference, with the outcome of its attestation (attested, rejected, or not attested) and the releaser’s two confirmations in it, that the output was checked for its intended use and that its residual risk was accepted, each true, false, or null where not stated and null without an attestation, or is null for a run that wrote no QC pack (D-016). Itsface_reviewsection gives, under the Clean Recognizable Visual Features Option, the opaque reference of the earlier run’s QC pack whose face verdicts the run followed, and how many series of CT Image, Enhanced CT Image, and Legacy Converted Enhanced CT Image instances the run defaced, of them how many around a target in the block, and how many it did not, by reason (D-050), and, inrt_doses_in_face_block, of the RT Doses that it released or held with more dose in a defaced series’ face block than it sets to zero there, how many it held without a reviewer’s choice, and, by the choice that it applied, written as received or set to zero there anyway, how many it held and the output name of each that it released, each sorted (D-051), and, inundefaced_in_defaced_frame, of the instances that it released or held in a defaced series’ Frame of Reference, naming none, or referring to a defaced slice, whose outlines, pixel data, or deformation grids it did not clean of the face, or cleaned in their own frame but not of a defaced slice that they refer to in another, how many it held without a reviewer’s verdict of their own, the output name of each that it released on one, sorted, and how many it held with one (D-050), and is null under any other policy (D-046). Itsredaction_reviewsection gives, under the Clean Pixel Data Option, the opaque reference of the earlier run’s QC pack whose redaction verdicts the run followed, how many of the source files that those verdicts accepted or revised were reviewed with every frame required (every-frame) and how many with only the frames with a region required (flagged-frames), and how many frames of those files the reviewer was not shown, and is null where the run was given none (D-048, D-059). Itspixel_regionssection counts, under the Clean Pixel Data Option, the regions that the option blacked out in the instances that the run released or held without a reviewer’s verdict, each region once in each frame that has it, by what gave them, the text finder (detected) or a reviewed region rule (rule), an identical copy counting as the instance it copies, and is null under any other policy (D-037). Itsreadinesssection gives, under thepublic-releasepreset, whether the run is ready for public release, the references of the reviewed QC pack and of the risk assessment that it checked, each null where it had none, and the reason code of each of the three gates, statistical, pixel and face, and attestation, null where it passes, and is null under any other policy (D-017, D-053). Itsreleasedsection lists the output name of each released instance, sorted (D-026). Itssequesteredsection names each sequestered instance by a random label for the run, such asS-0007, with each reason: the stage that sequestered it (scope, admission, which refuses a source file and sets it aside, the first pass’s references, the walker, the run’s own checks, the transform, including descriptor cleaning, the writer, the check that the source is preserved, or the release gate), the stage’s reason code, the attribute’s tags without items from the walker, and from the release gate where its reason names one, and, from the walker only, the action and the VR; for an instance of an unsupported IOD, the reason also gives the IOD as PS3.4 Table B.5-1 names it without “IOD”, such asUltrasound Image, never a value from the instance (D-010, D-026). Itsheld_for_reviewsection counts the instances held for review by stage (descriptor cleaning’s ROI names, itsdescriptors, the values of another option’s attributes that the reviewed descriptors list decides on, such as Allergies under Retain Patient Characteristics (D-038), Clean Pixel Data’s pixel data (D-037), the face review (D-046), including a CT series with a target in its face block that the run cannot keep within its slices or an eye ROI that disagrees with its globes and an RT Structure Set, RT Dose, PET, or Nuclear Medicine instance beside a defaced CT series that the run does not clean (D-050), a reviewed RT Structure Set whose contours the run writes otherwise (D-052), or an RT Dose with too much dose in a defaced series’ face block to set to zero there, or one set to zero there on a reviewer’s choice whose grid as set to zero no reviewed QC pack has shown (D-051), or the release gate) and reason code, each instance once for each reason however many of its names or attributes have it, and names none of them (D-009). The labels areS-0001toS-nfornsequestered instances, in an order drawn at random. Itsroi_namessection counts the ROI Names of the structure sets that descriptor cleaning cleaned in the run, each name by its outcome (renamed, empty, kept, mapped, emptied, held, or emptied unreviewed), and the distinct names sent for review, whether then held or emptied unreviewed, each once for each of its reasons, as the confidential QC pack lists them, and names none of them (D-009). Itsdescriptorssection counts the values of the free-text descriptors that descriptor cleaning read in the run, each value by its outcome (empty, kept, kept by vocabulary, mapped, emptied, held, or emptied unreviewed), the distinct values, each of one attribute, that it did not clean, each once for each of its reasons, and the elements that took the action that the policy gives them without Clean Descriptors, as the confidential QC pack lists them, and names none of them (D-009). Itsicc_profilessection counts the ICC Profiles that D replaced in the instances that the run released or held for review, an identical copy counting as the instance it copies: those it replaced with the source profile cleaned of everything but its colorimetry (cleaned), and those it replaced with the fixed sRGB profile, by the reason code of why the source could not be cleaned (replaced), such asdevice-classortag-data(D-021). Itsreference_findingssection counts the instances that have each kind of first-pass finding that the run reports without acting on it, such as a dangling reference, each instance once for each kind, an identical copy counting as the instance it copies, and names none of them (D-026). Itspixel_riskssection counts the released instances, and those held for review, that show each risk in their pixel data (burned-in text, a reconstructable face, or a possibly disclosed body weight), and each indicator of it, among them a CT, MR, PET, or RT Dose volume, a localizer, an RT Image, a Nuclear Medicine image, a Segmentation, a Parametric Map, the head or neck, values scaled or mapped to an SUV, and unreadable evidence, each instance once for each, an identical copy counting as the instance it copies, as the confidential QC pack lists them, and names none of them (D-015). Itssearch_coveragesection counts the source values that the residual search did not search, in full or in part, by attribute and reason, each value once for each reason however many of its forms that reason left out, at the instance that holds it, although each search of its subject’s files looks for it (D-027). Itsexempted_findingssection counts the released instances with a residual finding inside the data set that an exemption kept from review (D-032, D-039, D-042), by the exemption, the attribute of the source value, and the attribute in which it was found, each by its tags without items, each instance once for each, and names no value; the QC pack lists each finding by instance and place (D-032). Itssource_gapssection counts, by attribute and Type, the instances whose source lacks an attribute that their IOD unconditionally requires, which the run reports and never acts on (MIDI-BP-03); the QC pack lists each by instance and place. Itsstructural_checkssection summarises the engine’s checks that the release is well formed and refers to itself as the source did, as the maintainer decided on 6 October 2026: for the first pass’s references (references), the transform’s check that each written instance keeps the attributes its IOD requires where its source had them, with the source’s own gaps (iod-requirements), and the second pass’s check of what was written (written-references), always in that order, how many instances the check sequestered, which the report refuses to put above those that itssequesteredsection lists with the check’s reasons, and how many it reported without acting on them, each instance once, an identical copy counting as the instance it copies, naming none; the QC pack lists each reported finding by instance, including a written reference to an instance that was not written (D-026). Itsstudies_with_several_patientssection gives the run’s choice for a study whose instances name several patients,stop, the default, orsequester, and how many such studies the run sequestered, whose instances itssequesteredsection gives with the reasonstudy-with-several-patientsof thereferencesstage, naming neither a study nor a patient (D-026). Every field is built from the policy, the engine’s own files, the versions that run it, the keyed digests of the reviewed-names and reviewed descriptors lists and of the reviewed region rules, the technique vocabulary’s digest, the digest of the text finder’s class and description of its method, and codes and tags that the engine defines, never from a DICOM value directly, and as a backstop, writing the report refuses any field that is not a digest, a version, a known edition, preset, or option, a file name or path within the engine’s package or, for an outside module, within PyMedPhys, a QC pack’s or a risk assessment’s reference, an attestation outcome, a readiness gate’s reason code, whether the run is ready, or a confirmation given only with an attestation, an output name listed once, one of the run’s labels, a path of tags, a code that the engine defines, an IOD that Table B.5-1 names and the release does not support, a key’s scope or a project key’s identifier, a positive count, the descriptors’ count of elements that fell back and the count of cleaned ICC profiles, each from 0, a count of regions from 0, given exactly under the Clean Pixel Data Option, a count of RT Doses from 0, given exactly under a face review, a redaction review’s counts of files by review mode and of frames not shown, from 0, given exactly with its reference, or a structural check’s count from 0, or the run’s choice for studies with several patients with a count from 0 of those it sequestered, which is 0 where it stops at them. A change to its fields takes a new format label.Each run also writes a conformance statement generated from the rule tables and the effective policy, beside the release report at the root of the release, since it holds no instance value. It covers everything E.1.3 requires, the descriptions that E.3.5, E.3.6, E.3.7, and E.3.10 require for selected options, and each interpretation recorded in this document.
It is generated as CommonMark from the policy, the pinned tables, and the engine’s parameters, so it is regenerated whenever they change and never edited by hand, and the same inputs always give the same text. It names tags, actions, and parameters, never a value from an instance. It lists the action that the engine applies to each attribute, with each compound action, and each plain X, Z, and D, resolved by Type at every place where a supported IOD defines the attribute, other than within a sequence that is removed with its contents (D-020), and says why where that is not the policy’s action, as for the engine’s own removals and a sequence to which the policy gives C. It describes the rules that give every other element its action (D-022), the values that Z, D, and U write (D-003, D-005, D-021), how dates and times are handled without a Retain Longitudinal Temporal Information Option (D-006, D-023), and how Modified Dates modifies them (D-007, D-039), what the residual search covers and lists as not searched (D-027), and how the release report names sequestered instances by labels and counts the values that the residual search does not search by attribute and reason, with per-instance detail only in the confidential QC pack (D-016, D-026, D-027), how ROI Names are cleaned where the policy gives ROI Name C (D-009), gives the policy’s method digest (D-024), and describes the markers that each instance gains as the engine computes them for the policy (D-012).
Where the engine does not yet decide something that the statement must describe, the statement lists it under “Not yet described” and makes no conformance claim. Where an IOD requires an attribute to which the policy gives a plain X, the statement names the enclosing sequence or overlay group that D-020 removes with it, or the sequestration that it decides instead, as the walker plans them. A preset is enabled only once its statement lists nothing there.
Each release publishes a traceability matrix from requirements to tests (D-018). The documentation shows the register’s part of it, without test results, as the requirements matrix, which every documentation build generates.
Presets#
Preset |
Intended use |
Profile and options |
|---|---|---|
|
Baseline transformation |
Basic Profile, with no options |
|
Baseline transformation that keeps cleaned descriptors, such as structure names that match TG-263 |
Basic Profile; Clean Descriptors |
|
Copies for non-clinical treatment planning system databases, such as research copies of patient data, or duplicates of phantom data that must coexist without UID conflicts |
Basic Profile; Retain Longitudinal Temporal Information with Modified Dates; Retain Patient Characteristics; Retain Device Identity; Clean Descriptors; Clean Structured Content |
|
Collections being assessed for unrestricted public sharing |
Basic Profile; Retain Longitudinal Temporal Information with Modified Dates; Clean Descriptors; Clean Structured Content; Retain Safe Private; Clean Recognizable Visual Features |
These are the target option sets. Each preset’s policy is composed from its options and validated before processing (D-011). A preset is enabled only once its behaviour is implemented and validated for the documented input scope. No preset is enabled yet; the first supported release is to enable all four, and every option, and waits until every one is validated (Scope). A run can select a custom option set in place of a preset (D-033), which is validated in the same way, except that every conflict between its options is rejected, so its policy can claim conformance, unlike that of
tps-import. A custom option set is enabled only whilebasicand each of its options are enabled, an option being enabled once its behaviour is implemented and validated; no option is enabled yet. Selecting a preset or options is not evidence of conformance (D-011).Profile implementations strictly match DICOM definitions. A preset named after a profile, such as
basicorbasic-clean-descriptors, applies exactly the profile and options its name gives, and any claim a preset makes names exactly the profile and options it applies (D-011).basictherefore stays exactly the Basic Profile, with no options, and the Clean Descriptors Option that the first supported release includes has a preset of its own rather than joiningbasic.tps-importmakes no PS3.15 conformance claim, because its Retain Device Identity and Modified Dates options conflict (D-007). Its output is marked as D-012 describes.tps-importwrites synthetic birth dates (D-008), cleans ROI names asbasic-clean-descriptorsdoes, keeping no name that has not been reviewed apart from those that automatic cleaning writes in the vocabulary’s spelling, and retains other cleaned descriptors only after pooled human review, otherwise applying the actions that its policy gives them without Clean Descriptors (D-009). Each run with a new key gives UIDs and patient pseudonyms unrelated to earlier copies, so several copies of one source, such as a phantom, can coexist in one planning system (D-003).public-releaseomits Retain Device Identity, because device serial numbers and machine names can identify an institution and, with dates, individual treatments. It omits it whatever a risk assessment of the collection finds, as the maintainer decided on 24 October 2026 (D-017).public-releaseselects the Clean Recognizable Visual Features Option, as the maintainer decided on 25 October 2026, so that the preset can release a collection whose images can show a face by removing the face from CT and releasing only what a reviewer finds free of one; under the preset, an assessment of facial risk releases no face (D-017). A run under the preset therefore removes the face block from each CT series in which it finds one, cleans the same region of the RT Dose, RT Structure Set, PET, and Segmentation instances in a defaced series’ frame, or holds them, and holds every Nuclear Medicine image there (D-050 to D-052), and holds every instance that can show a face unless a reviewer found none in the previews of the pixel data and contours that it writes (D-046). It needs the attested QC pack of an earlier run of the same files, so the first run of a collection under the preset is given one with no face verdicts, which holds every such instance, and the verdicts on that run’s pack release the next run’s (D-050).tps-importandpublic-releaseselect the Clean Structured Content Option, as the maintainer decided on 25 October 2026, once the engine removes a content item that cannot be kept on its own rather than the whole tree (D-047). Under either preset, a supported Structured Report, such as a radiation dose report, is released with its content tree cleaned by the concept names of its content items, rather than sequestered for the D that the Basic Profile gives Content Sequence, and Acquisition Context Sequence and Specimen Preparation Sequence are cleaned in the same way where the IOD defines them (D-047).tps-importandpublic-releasekeep their names, although they are named after their purposes rather than after a profile: a name that listed their options would be long and would hide the purpose, and neither claims a profile that it does not apply, sincetps-importmakes no conformance claim and each preset’s conformance statement names its options.Profile conformance and readiness to release are reported separately.
basicandbasic-clean-descriptorsoutput is not thereby ready to share.tps-importoutput is for non-clinical databases only.public-releaseoutput also needs a statistical assessment, pixel and face review, and a human QC attestation (D-016 and D-017).
Decisions#
These are the active design decisions, not statements that the code implements them. Decision identifiers are stable and never reused. A number reserved for a decision still being drafted is marked by an HTML comment where its section goes, such as <!-- D-040 -->, which the pull request that records it replaces, so that decisions recorded in parallel change no line in common and the sections stay in numeric order.
D-001: Tables generated from a pinned edition#
Decision.
A development command generates the L1 tables from the pinned edition of the standard, currently 2026d. It downloads the published HTML pages, verifies each page’s SHA-256 against the pinned digest, and parses them with
html.parser. Most pages are NEMA’s chtml pages, one per section. PS3.3’s module and macro tables span dozens of those, so PS3.3 is read from its single-page HTML, which marks up tables in the same way. It records the edition, the source digests, and a digest of the generated content. The PS3.6 data dictionary and Annex A tables, and the PS3.16 coding schemes, context groups, and Annex O mapping, parse from the HTML as reliably as the Annex E tables, so no DocBook XML parser is needed.The repository and the package keep the generated tables, not the standard’s source files. Each generated file carries the copyright attribution
DICOM PS3.x <edition>, © NEMA, such as “DICOM PS3.15 2026d, © NEMA”.A loader reads each table, checks each row’s fields, types, and actions, and rejects a table whose rows no longer match the digest recorded in the file. This catches a table edited without updating that digest; it does not authenticate the file.
Table E.1-1a must define exactly the action codes the engine implements, so a new edition that adds or removes a code fails generation until the engine handles it.
PS3.3 Types are generated only for the composite IODs, ahead of the releases that support them: each table of PS3.3 Annex A titled with an IOD’s name and “IOD Modules”, such as “CT Image IOD Modules”, 174 tables in 2026d. The first supported release supports 61 of these IODs: CT Image, Enhanced CT Image, Legacy Converted Enhanced CT Image, MR Image, Enhanced MR Image, Enhanced MR Color Image, Legacy Converted Enhanced MR Image, MR Spectroscopy, Positron Emission Tomography Image, Enhanced PET Image, Legacy Converted Enhanced PET Image, Nuclear Medicine Image, RT Structure Set, RT Plan, RT Dose, RT Image, Enhanced RT Image, Enhanced Continuous RT Image, RT Segment Annotation, RT Radiation Set, C-Arm Photon-Electron Radiation, Tomotherapeutic Radiation, Robotic-Arm Radiation, RT Beams Delivery Instruction, RT Brachy Application Setup Delivery Instruction, RT Radiation Set Delivery Instruction, RT Beams Treatment Record, RT Ion Plan, RT Ion Beams Treatment Record, RT Brachy Treatment Record, RT Treatment Summary Record, Spatial Registration, Deformable Spatial Registration, Segmentation, Surface Segmentation, X-Ray Radiation Dose SR, Enhanced X-Ray Radiation Dose SR, Radiopharmaceutical Radiation Dose SR, Patient Radiation Dose SR, Basic Text SR, Enhanced SR, Comprehensive SR, Comprehensive 3D SR, Extensible SR, Key Object Selection Document, Mammography CAD SR, Chest CAD SR, Colon CAD SR, Procedure Log, Spectacle Prescription Report, Macular Grid Thickness and Volume Report, Waveform Annotation SR, Parametric Map, Real World Value Mapping, and the Grayscale, Color, Pseudo-Color, Blending, XA/XRF Grayscale, and Variable Modality LUT Softcopy Presentation States, and Encapsulated PDF. Generated Types do not make an IOD supported: its instances are sequestered until a release supports it (D-010). PS3.3 publishes 18 other tables titled “IOD Modules” in 2026d, for the Normalized IODs of Annex B and the Basic Directory IOD of Annex F, and their Types are deliberately not generated. No instance of them is de-identified: Normalized IODs describe the attributes of DIMSE-N services, so their module tables give no Types apart from the SOP Common Module’s, since PS3.4 sets their attributes’ requirements for each service, and the Basic Directory IOD is a DICOMDIR, which is never passed through (D-016). For each IOD, its modules table gives each module’s information entity, section, and usage, with any condition; a section number can end in a letter, as C.7.6.4b does. Each module’s attribute table is the one in that section titled with the module’s name and “Module Attributes”, such as “Patient Module Attributes”. Attribute tables, and every macro table they include, are kept as published, without descriptions: each row’s nesting depth, name, tag, and Type, or the macro an “Include” row adds. Generation checks every tag against the data dictionary and allows nesting only below a sequence, or one level below an “Include” of a macro whose only top-level attribute is a sequence, whose items the nested rows extend, as Table C.18.4-1 “Image Reference Macro Attributes” extends Referenced SOP Sequence (0008,1199) of Table C.18.3-1 “Composite Object Reference Macro Attributes”. A table may include itself below one of its own sequences, as Table C.17-6 “Document Relationship Macro Attributes” does in Content Sequence (0040,A730) and Table C.38.2-3 “Inventory Reference Macro Attributes” does in Incorporated Inventory Instance Sequence (0008,0422), so that content nests to any depth; generation rejects any other cycle of includes.
Errors in the published tables are corrected by named corrections in the pin. Each replaces text that must occur in exactly one row of its table, or in a stated number of rows where identical cells need it, counting its title and header as rows, so a correction fails generation once an edition changes that text. In 2026d there are 18: usages separated from their conditions by an en dash, a hyphen without a space, or nothing; module tables titled differently from their modules, and a macro table titled differently from its section, “Frame VOI LUT With LUT Macro”; two modules listed with the wrong section; a name column headed “Attribute name”; an “Include” row with a space after its “>” characters; and the X-Ray Grid Macro’s Include of the X-Ray Grid Description Macro, published outside the macro’s only sequence, X-Ray Grid Sequence (0018,9555), whose Grid (0018,1166) it describes, which the pin nests in that sequence, as the X-Ray Filter Macro nests its description in its own.
The Multi-frame Functional Groups Module (C.7.6.16), and three other modules like it, include the IOD’s Functional Group Macros in the items of their Functional Groups Sequences: of the Multi-frame Functional Groups Module, the one item of Shared Functional Groups Sequence (5200,9229) and the item for each frame of Per-Frame Functional Groups Sequence (5200,9230). Each IOD whose modules include them lists its macros, each with a usage, in a table of Annex A titled with its name and “Functional Group Macros”, such as Table A.38-2 for Enhanced CT Image, except that the text gives the Enhanced MR Color Image IOD the Enhanced MR Image IOD’s table, which the pin records by the two IODs’ names. Generation keeps the row that includes the macros as an “Include” of them, records the IOD’s macros with their usage and condition, and keeps each macro’s attribute table, the one in its section titled with its name and “Macro Attributes” or “Functional Group Macro Attributes”. It fails if an IOD’s modules include Functional Group Macros and no table lists them, or a table lists them and no module includes them; if such a table names no IOD of Annex A, or an IOD has two; if rows are nested below the row that includes them; and if a macro does not define exactly one top-level attribute, a sequence, or includes Functional Group Macros itself, since each Functional Group is one sequence (C.7.6.16.1.1).
The three real-time IODs, Real-Time Video Endoscopic Image, Real-Time Video Photographic Image, and Real-Time Audio Waveform, are left out: their Current Frame Functional Groups Module gives Current Frame Functional Groups Sequence (0006,0001), which PS3.6 defines in Table 9-1, not in the data dictionary of Table 6-1. The pin names each by its table and name, since table numbers can change between editions, and records the attribute it lacks, (0006,0001). Generation fails if a named table is not the modules table of Annex A of the IOD named with it, if an IOD it names can be generated or fails for any reason other than the attribute recorded with it, or if an IOD it does not name cannot be generated. In 2026d, Types are generated for 171 of the 174 composite IODs, including 30 of the 33 whose modules include Functional Group Macros, such as Enhanced CT Image and Segmentation.
The loader checks both PS3.3 files when it reads them, and expands an IOD’s modules when its Types are first needed, following every “Include”, into each attribute’s Type in each module and within each enclosing sequence, and keeps the result. An Include by which a table includes itself is kept as a reference back to that table rather than expanded again, so the attributes below that sequence have the same Types at every level of nesting, and the loader finds them at any depth. An Include of Functional Group Macros expands the IOD’s macros there, so in both Functional Groups Sequences of the Multi-frame Functional Groups Module, and each attribute defined in a macro names it. A macro’s usage applies to the macro as a module’s does to the module: whether an instance must, under its condition must, or may include the macro’s sequence, in the Shared item or in each Per-Frame item, and the Types of the macro’s attributes apply wherever it is included. A condition, such as Frame Content’s “May not be used as a Shared Functional Group.”, is kept as text, and the macro is expanded in both sequences, as C.7.6.16 defines them. An attribute of a repeating group, such as Overlay Data (6002,3000), matches its group’s definition, (60xx,3000). Different modules can give an attribute different Types, and an attribute the IOD does not define has none.
An instance names its SOP Class in SOP Class UID (0008,0016), not its IOD, so PS3.4 Table B.5-1, which gives the IOD of each Standard Storage SOP Class, is generated whole from its chtml page. The engine finds an instance’s IOD, and with it the Types, from its SOP Class UID without trailing NUL and space padding, as it does before replacing a UID (D-003), since PS3.5 Section 9.1 pads a UID of odd length, such as each of the first release’s SOP Class UIDs, with a NUL. PS3.3 Annex A publishes a modules table for the IOD of every Storage SOP Class in Table B.5-1, and none of them is left out, so each of those SOP Classes has Types. Ten generated IODs in 2026d, such as Hanging Protocol and Color Palette, have SOP Classes that other parts of PS3.4 define, so no SOP Class of Table B.5-1 finds them. Any other SOP Class, including one the table does not list, such as a retired or Private SOP Class, has none and is outside the supported scope (D-010).
Table E.3.4-1, the concept names of the content items that the Clean Structured Content Option cleans, is generated from its own chtml page. Each row gives a code, the value type of the content items it names, whether PS3.16 retires the code and uses it in a template, and the actions of the Basic Profile and of the seven options the table has columns for, as Table E.1-1 gives them for an attribute. A code can have a row for each of several value types with different actions, so a row is identified by its coding scheme designator, code value, and value type. The table gives a Coding Scheme Version in brackets after the designator where it gives one, as in “NCDR [2.0b]”, and generation records the designator and the version separately. Only rows whose coding scheme the pin keeps are generated, DCM, LN, and SCT in 2026d (207 of 214 rows); the pin names the schemes it leaves out, NCDR, NCIt, and UMLS, and generation fails if a row’s scheme is in neither list or a scheme in them has no row. A content item whose concept name is coded in a scheme that the pin leaves out cannot be matched, so under the option its sequence takes its Basic Profile action (D-047).
The LOINC rows’ codes, and the 3 LOINC codes of the supplementary rows (D-047), are named in
_loinc/loinc_terms.toml, with each code’s long common name and status from LOINC 2.83; generation fails for a LOINC row whose code it does not name. The generated rows keep DICOM’s Code Meanings._loinc/LICENSE-LOINC.txtholds LOINC’s notice and licence, whichlicense-fileslists, and the README carries the notice. LOINC 2.83 deprecates 11955-2 (Date of last menstrual period), which PS3.16 2026d still uses, so its row is generated as the table gives it.PS3.16 Table O-1, which maps the SNOMED ID of each SNOMED code that DICOM has used, the “SNOMED-RT style” Code Value of the retired designators SRT, SNM3, and 99SDM, to the SNOMED CT Concept ID of the same concept (PS3.16 Section 8.1), is generated from Annex O’s chtml page with its Concept IDs and SNOMED IDs, 8,161 rows in 2026d, and without its Fully Specified Names, which nothing looks up. Each Concept ID must be 6 to 18 digits without a leading zero, with a concept’s partition identifier and a valid Verhoeff check digit, and each SNOMED ID one or two capital letters or digits, a hyphen, and capital letters or digits, in at most 16 characters; neither may repeat, so that each SNOMED ID maps to one concept. 2026d publishes one row twice, the same both times, which the pin names and generation keeps once; generation fails if a row the pin names is not published exactly twice, the same both times, or if any other Concept ID or SNOMED ID repeats. A content item whose concept name is coded by a retired designator is matched through it (D-047).
PS3.3’s Enumerated Values and Defined Terms of the attributes of VR CS are generated from the same page as its module tables, and the Defined Terms of Body Part Examined (0018,0015), for which PS3.3 refers to PS3.16 Annex L, from that annex’s chtml page, for the residual search’s exemptions (D-032).
The paragraphs of Annex E that contain “shall”, outside Notes and tables, are generated too, from every chtml page of Annex E, each of which the pin lists: 13 pages in 2026d, chapter_E.html and the pages of E.2, E.3, and E.3.2 to E.3.11. Generation starts at chapter_E.html and follows each page’s Next link until it leaves Annex E, and fails if it reaches a page that the pin does not list or a page twice, does not reach a page that the pin lists, or meets a division of a page that it neither reads nor skips, so that a new page or a new kind of content is reviewed before it is read. A paragraph is a
pelement within a section of Annex E; those in Notes and tables are skipped. Each is recorded with its section, its page, its anchor, and its text with whitespace normalised. A paragraph that a list follows introduces it, and the list’s items are added to its text after a blank line, one per line, each marked “-” or numbered as published, rather than being read as paragraphs of their own; the items of a list that a paragraph without “shall” introduces are paragraphs in their own right, as each of the de-identifier’s steps in E.1.1 is. In 2026d there are 35. The register’s PS3.15 entries must be exactly these paragraphs, with the same sections, links, and text, in the same order, which a test checks. Their identifiers stay the register’s, so a paragraph that a new edition adds takes a new identifier rather than renumbering its section.pymedphys dev deid-tables --check-currentdownloads the pinned pages from NEMA’s unpinnedcurrent/directory, generates each table from them with the same development-only parsers and the pin’s corrections, and compares the digest of each table’s rows with the one recorded in the committed table, without writing the tables. It names the edition the pages give, each table that would change, each page that could not be fetched, and each table that could not be generated, with the pages it read and the type of error, never quoting a page. It exits with status 1 when a table would change and 3 when a page could not be fetched or a table generated, and--jsonalso writes the result as JSON. A monthly workflow runs it and opens or updates one issue when a table would change, a page fails, or the check stops without a result. The workflow is defined in.github/workflows/deid-edition-check.yml. Its check job can only read the repository, and only the job that opens the issue, which runs no repository code, can write issues. Because the paragraphs of Annex E are generated too, the check reports an edition that adds, changes, or removes one, or adds a page to Annex E, and moving the pin regenerates them, so the register’s test fails until its PS3.15 entries match the new edition. Generated files are never edited by hand.
Rationale. The legacy keyword list was transcribed by hand and has drifted: it has 217 entries, drawn from Supplement 142, while Table E.1-1 in 2026d has 657 rows. The standard is revised about five times a year. NEMA holds the copyright in the standard, and each table records that attribution. Table E.3.4-1 also contains SNOMED CT, LOINC, NCDR, NCIt, and UMLS codes, which carry their own terms. Its SNOMED CT codes belong to the subset of SNOMED CT that DICOM publishes, which the reviewed head and neck regions also use, so their rows are generated. Table O-1 is part of the same subset (PS3.16 Section 2.19), since it maps only SNOMED codes that DICOM has used, so it is generated on the same basis; only its codes are generated, since only codes are looked up, which keeps SNOMED’s descriptions out of the package. It is generated whole, rather than only for Table E.3.4-1’s ten SNOMED CT concepts, so that a code that it maps to a concept the table does not list can be treated as unlisted, while a code that it does not map still cannot be matched. Its repeated row is named in the pin, as corrections are, so that an edition that changes it is reviewed. Its LOINC rows are generated too, because a content item coded in LOINC cannot otherwise be matched, so most TID 2000 imaging reports, whose titles and section headings CID 7000 and CID 7001 code mostly in LOINC, and Macular Grid reports, whose measurements TID 2101 codes in LOINC, would be sequestered under the option. The LOINC names are kept in their own file so that the generated table keeps Table E.3.4-1’s columns and DICOM’s Code Meanings. The rows of the other schemes are left out until their terms are checked against the policy for bundled data; leaving them out keeps nothing identifying, because a content item coded in one of those schemes makes its sequence take its Basic Profile action (D-047), and only the options that would retain such an item lose it. The standard library parsers add no dependency and only ever read verified publications, in a development-only tool. PS3.3 tables are kept as published because expanding each macro in each IOD would repeat shared modules and macros: the 171 IODs generated in 2026d expand to about 709,000 definitions, and the first supported release’s 14 to about 79,400, but the two files that hold them and their 664 tables take 2.0 MB. Expanding each IOD only when its Types are first needed keeps loading the tables quick however many IODs they hold. For the same reason each IOD records its Functional Group Macros, and the module that includes them keeps the row that does, rather than each IOD having a copy of that module with its macros expanded: 29 IODs share the Multi-frame Functional Groups Module, each with its own macros. Table B.5-1 is small (173 rows in 2026d), so it is generated whole. Generating the Types of every composite IOD means that every stored object type’s Types and reference sites are known, so no later release, the reference graph, or the resolution of compound actions is limited by which tables were generated, and instances that are sequestered can still have their references recorded. The costs are larger generated data, review load, and edition-check issues on most editions, since almost every edition changes some IOD. The monthly check compares generated content rather than source pages, so it raises an issue only when the tables would actually change; comparing source digests alone was rejected because it would raise one for every edition, about five a year, even when no generated table would change, which trains people to ignore it. The parser executes nothing from the page, and a page that cannot be parsed opens an issue itself, as does a check that stops without a result, so the check never fails silently. The report quotes no page, so the issue reproduces none of the standard’s text. Errors in the published tables are corrected by name, rather than by a parser that accepts variants, so that an unexpected layout in a later edition still fails generation. The real-time IODs are left out until Table 9-1 is generated too, rather than generated without Current Frame Functional Groups Sequence, so that no consumer can read incomplete Types; for the same reason the loader rejects an IOD whose modules include Functional Group Macros that it does not list. The Annex E paragraphs are generated, rather than compared by hand with each new edition, because the register reproduces them verbatim, where a changed word is easily missed, and because a hand comparison happens only when the pin moves, so an edition that changed only a paragraph went unnoticed until then. They are compared with the register by a test rather than written into it, since the register’s identifiers, statuses, and notes are curated. Following the Next links, rather than reading only the pages the pin lists, is what lets generation notice a new page of Annex E.
Tests. Regeneration reproduces the committed tables and digests; a source file with a different digest is rejected; a table whose rows differ from their recorded digest, or whose rows have the wrong fields, types, or actions, is rejected; and every generated file carries the copyright attribution. For Table E.3.4-1, columns are matched by header text; a code with rows for two value types, and a designator with a version, are generated; a row with a malformed code, designator, value type, flag, or action, a repeated designator, code value, and value type, or a coding scheme that the pin neither keeps nor leaves out fails generation, as does a scheme the pin names without a row; counts and spot rows match the published table; every scheme the pin names is in PS3.16 Table 8-1; and the table’s value types are the Enumerated Values of Value Type (0040,A040) other than NUMERIC, which the Content Item Macro uses where the table, following PS3.3 Section C.17.3, gives NUM. For LOINC, generation fails for a LOINC row whose code the terms file does not give; the terms file gives exactly the LOINC codes of the generated table and the supplementary rows, and its loader rejects another schema, a missing LOINC version, fields other than LOINC_NUM, LONG_COMMON_NAME, and STATUS, a code with an invalid check digit, an empty or overlong name, an unknown status, and a repeated code; the notice file and the README carry LOINC’s notice; and the package’s licence metadata lists LOINC’s licence, which the distribution check expects. For Table O-1, columns are matched by header text, the names are not generated, and the second of a row the pin names is left out; an invalid Concept ID or SNOMED ID, a repeated Concept ID or SNOMED ID other than the named row’s, a named row that is not published exactly twice the same, and a table without rows fail generation; the loader rejects invalid and repeated identifiers; the 2026d table has 8,161 rows and maps each SNOMED CT concept of Table E.3.4-1; and a SNOMED ID maps to its SNOMED CT code only under SRT, SNM3, or 99SDM, as published, without padding or another case. For PS3.3, only the IOD Modules tables of Annex A are selected, and each is generated or named in the pin; each IOD whose modules include Functional Group Macros has exactly one table of them, its own or the one the pin gives it, and every such table belongs to an IOD of Annex A; a row that includes them becomes an Include of them, while one in other words is rejected, as are rows nested below it, a macro without a table in its section, and a macro that does not define exactly one sequence or that includes Functional Group Macros; the pin leaves out exactly the IODs that cannot be generated because of an attribute the data dictionary lacks, which a test also lists with the attribute each lacks, and generation fails if one of them first lacks an attribute other than the one recorded with it; every other composite IOD is generated, including the enhanced multi-frame IODs; each correction applies to its stated number of rows, and fails generation otherwise; merged cells are expanded; modules are found by section and title, including a section that ends in a letter; macros are reached through nested includes; rows nested below an “Include” extend the included macro’s only sequence, and nesting below an Include of any other table is rejected; spot Types match the published tables, including different Types in different modules and sequences, for IODs other than CT Image and the RT IODs, such as MR Image, Positron Emission Tomography Image, RT Image, and RT Beams Treatment Record; spot Types inside both Functional Groups Sequences, such as Pixel Spacing (0028,0030), Type 1C, in Pixel Measures Sequence (0028,9110) of Enhanced CT Image and Segmentation, each macro’s usage and condition, and each macro in every sequence that includes the macros; an IOD is expanded only when its Types are first needed; Types are found at every level of a table that includes itself, such as Relationship Type (0040,A010), Type 1, in Content Sequence items nested three deep in an Encapsulated PDF; and malformed nesting, missing tables, and any other cycle of includes, including a table that includes itself outside its own sequences, are rejected. For PS3.4, every Storage SOP Class is a current SOP Class in PS3.6 Table A-1; the IOD of every Storage SOP Class is generated, and every Storage SOP Class finds it; the generated IODs that no SOP Class of Table B.5-1 names are listed; and the SOP Classes of CT Image, RT Structure Set, RT Plan, and RT Dose find their IODs, with or without padding and when read from a file, as do the SOP Classes of other generated IODs, such as MR Image, RT Beams Treatment Record, Enhanced CT Image, and Segmentation, while SOP Classes that the table does not list find none, and so does one that it lists whose IOD has no generated Types, as when a later edition lists an IOD that the pin leaves out. The edition check downloads each pinned page from
current/; reports no change for the pinned edition’s pages, or for a page that changes without changing a table; reports exactly the table that a changed cell changes; reports a page that cannot be fetched or parsed, and the tables it prevents, without quoting the page, as a failure even when another table would change; and writes nothing but its report. For the Annex E paragraphs, only paragraphs with “shall” outside Notes and tables are kept, each with its section, page, and anchor, and with whitespace and zero-width characters normalised; the list that such a paragraph introduces is added to its text, marked “-” or numbered as published, even an item that says “shall” itself, while the items of a list that a paragraph without “shall” introduces are paragraphs of their own; the pages are read in the order of their Next links, whatever the pin’s order; generation fails on a page that the pin does not list, a pinned page that the links do not reach, a page reached twice, a page without exactly one Next link, a division that is neither read nor skipped, a paragraph with “shall” outside a section or without its anchor, an item of an introduced list that is not one paragraph, a repeated anchor, or no paragraph with “shall”; the generated file records every pinned page of Annex E, and 35 paragraphs in 2026d, which the register’s PS3.15 entries match exactly; the loader rejects a malformed section, page, anchor, or text, other fields, or a repeated anchor; and the edition check reports exactly the paragraphs as changed when a paragraph’s text or an item of the list it introduces changes, a paragraph with “shall” is added, or one no longer says “shall”, and nothing when only a Note or a paragraph without “shall” changes.
D-002: pydicom 3.0.2 minimum#
Decision. Require pydicom 3.0.2 or later, with no compatibility layer for pydicom 2, as the maintainer decided on 1 October 2026.
Rationale. The package declared
pydicom>=2.0.0, but continuous integration tested only the locked 3.0.2. The engine usesdcmwrite(..., enforce_file_format=True), added in pydicom 3.0. That call updates the Media Storage SOP Class and Instance UIDs but keeps other File Meta elements and any existing preamble, so the engine builds both itself. The engine also reads each element without pydicom decoding it, throughDataset.get_item(..., keep_deferred=True), which pydicom 3.0 added too. pydicom 3.0.0 and 3.0.1 are affected by CVE-2026-32711, a path-traversal flaw in reading DICOMDIR files that 3.0.2 fixes. The engine writes no DICOMDIR and never passes one through (D-016), but other PyMedPhys code and users’ own code read files with the same pydicom, so the minimum excludes the affected releases rather than leaving them installable.Tests. Continuous integration runs the de-identification tests with pydicom 3.0.2, the lowest release that this minimum allows, as well as with the locked version and the latest release (D-029).
D-003: UID replacement#
Decision.
Resolve each UID attribute’s effective action from the L1, L2, and validated L3 rules before transforming its value.
Semantic identifiers need explicit L2 rules. SOP Class UIDs, transfer syntaxes, and well-known coding-scheme and context-group UIDs are retained. Local coding-scheme identifiers and private codes are retained only when a reviewed L2 rule classifies them as non-identifying; this is stricter than Table E.1-1, which gives C only to the Code Sequences it lists (E.1.1, Notes 7 and 10 after Table E.1-1a). A UI attribute with no rule is rejected, never hashed merely because of its VR.
The L2 file
uid_roles.tomlgives every UI attribute of the pinned dictionary a role. Aninstanceattribute identifies an instance, event, entity, device, or organisation; every UI attribute that Table E.1-1 replaces has this role, as do instance UIDs the table omits, such as Target Frame of Reference UID (0018,991E). Adefinitionattribute identifies something a standard or vendor publishes: a SOP Class, transfer syntax, coding scheme, context group, mapping resource, or template.A value that the pinned tables register (PS3.6 Annex A and PS3.16 Tables 8-1 and 8-2) is retained whatever the attribute’s role, because it names a public definition rather than an instance. Examples are a well-known frame of reference (PS3.6 Table A-2) and the Universal Coordinated Time synchronization frame of reference. This interprets U for such values, and the conformance statement records it. Any other value is replaced; in a
definitionattribute, where it may be a local definition under an institution’s root, the replacement is also reported.Where replacement is required, remove trailing NUL and space padding, then compute a 32-byte token with HMAC-SHA256 under the run’s key (D-004) and a UID-specific domain label. The replacement is the name-based SHA-1 (version 5) UUID of that token in a fixed namespace defined by PyMedPhys, written as a
2.25.UID of at most 44 characters. The namespace is the version 5 UUID ofhttps://docs.pymedphys.com/deidentify/uid-namespacein the URL namespace, and never changes.Use the same derivation for every occurrence, including nested references, File Meta Information, and retained private elements. The same key always gives the same replacement, within a run and across runs. A new key gives unrelated replacements, for example to import another copy of a phantom alongside earlier copies.
Replacement UIDs never use an organisation root.
Device UID (0018,1002) is replaced under the Basic Profile (U) and retained under Retain Device Identity (K).
Under the Retain UIDs Option, the UIDs to which Table E.1-1 gives K under it are retained, and every other UID is replaced as above (D-040).
Rationale.
Standards basis. PS3.5 B.2 derives
2.25.UIDs from UUIDs as defined by ISO/IEC 9834-8 and ITU-T X.667. X.667 defines the name-based SHA-1 UUID as version 5 (clause 14.3). Its Table 3 reserves versions 0 and 6 to 15, and a note in clause 12.2 expects any new format to use different variant bits, so the version 8 layout that RFC 9562 adds is not an X.667 UUID. X.667 does not limit names to text (Annex B), so the 32-byte token is a valid name. Using the token as the name keeps the standard version 5 construction; replacing its SHA-1 step with HMAC-SHA256 would not. A2.25.UID needs no registered root, whereas an organisation root can identify the institution (E.3.9 Note 2).Re-linking. The UUID’s name is a keyed token, so without the key, knowing a source UID does not reveal its replacement. Unkeyed hashes, as in the legacy pseudonymisation, and version 5 UUIDs of the source UIDs themselves both reveal it. Published SHA-1 collision attacks need inputs the attacker chooses, and without the key nobody can choose the HMAC outputs that form the names. A compromised key reveals the replacements of known source UIDs (D-004).
Uniqueness. A version 5 UUID has 122 variable bits, so the probability of any collision among \(10^9\) replacement UIDs is about \(10^{-19}\).
State. Replacements are computed from the key alone, so no UID map is needed: parallel workers need no coordination, output does not depend on the number of workers, and incremental export needs only the key. Random version 4 UUIDs would instead need a map equivalent to a crosswalk, protected, shared between workers, and kept for incremental export.
Tests. Known-answer vectors for the derivation; version and variant bits; length at most 44 characters; a role for every UI attribute, and the instance role for every UI attribute Table E.1-1 replaces; registered values retained under either role; consistent replacements across workers, nested references, File Meta Information, retained private elements, and incremental runs; unrelated replacements under different keys; Device UID under the Basic Profile and under Retain Device Identity; retained class, coding-scheme, and context-group identifiers; rejection of unclassified UIDs; and, after writing, both replacements and required retentions.
D-004: Keys and subject profiles#
Decision.
Keys are 256 bits from a cryptographically secure generator. An ephemeral key and its run-only state are discarded after the run, so generated values are consistent only within that run. A project key and its subject profiles are held by a custodian, so generated values stay consistent across runs, as incremental RT collections need.
Use a separate key for each project and recipient, with subject profiles isolated per key. Releases under one key are linkable by design. Separate keys separate only the generated values: pixel data, geometry, and retained attributes can still link releases, and each release’s assessment covers them (D-017).
Derivations for UIDs, patient identifiers, date offsets, and the keyed digests of the reviewed-names list, the reviewed descriptors list, and the reviewed region rules (D-024) are domain-separated. Each is an HMAC-SHA256 under the key of the version label
pymedphys-deid/1, the domain, and each input, every one preceded by its length, so no two domains or splits of the input share a message. A new derivation takes a new version label.Each key has a non-secret identifier derived from it. Reports may record the identifier, never the key.
Project keys and subject profiles are stored only in custodian-controlled locations outside output and QC directories, and never in logs, reports, or the PyMedPhys user configuration. A key file is JSON (
pymedphys-deid-key/1) holding the key and its identifier. It is created exclusively, so an existing file or symbolic link is never overwritten or followed, and with owner-only permissions where the platform enforces file modes; elsewhere writing it warns.The subject profile is the single source of truth for a subject’s date offset and synthetic values. They are derived at first export, persisted, and read back afterwards; a change of derivation never silently changes an exported subject.
A profile store is JSON (
pymedphys-deid-profiles/1) that records its key’s identifier and refuses any other key. It holds each subject under the key’ssubjectderivation of the identity, never under an identifier, with the values and the derivation version that produced them. It is replaced atomically, created with owner-only permissions where the platform enforces file modes, and kept out of the configuration directory and any protected directory, like a key file. Under an ephemeral key, profiles are kept for the run only.Incremental export needs both the key and the subject profile. Recipients receive neither.
Rotating a key starts a new domain of generated values. If a key or profile is lost, earlier exports cannot be extended consistently. A compromised key is treated as disclosure of the crosswalk, and affected releases are reassessed.
A run takes a project key and its profile store together: the private API’s
key_fileandprofile_store, or the private command’s--key-fileand--profile-store. A private module,python -m pymedphys._dicom.deidentify.key_command, creates a key file and prints only its identifier. Neither is in the public command line. Both refuse a project key unlessPROJECT_KEYS_ENABLEDinkeys.pyis set, before reading the key file or the store, and the flag stays off until the release PR, since the first supported release uses a run-scoped key (Scope). A run under a project key reads each subject’s date offset from its profile, records a new subject’s at first export, and saves the store before it writes the QC pack or publishes the release, so a store that cannot be saved publishes nothing. The release report’skeysection gives the key’s scope, run or project, and a project key’s identifier, and the conformance statement says which kind of key the run used. Series Numbers are still ranked within one run (D-022).
Rationale. Medical record numbers and similar identifiers have little entropy, so anyone holding the key can enumerate candidates and re-identify every subject: a project key is equivalent to a crosswalk. Profiles shared between keys would give every recipient the same shifted dates and synthetic values.
Tests. Key-file creation and permissions; refusal to write keys or profiles into output, QC, or configuration locations; stable key identifiers; offsets read from an existing profile after a derivation change; profiles isolated per key; consistent generated values across incremental releases; a demonstration that a key enumerates low-entropy identifiers; a project key refused while
PROJECT_KEYS_ENABLEDis off, and a key file or store inside a run’s directories or of another key refused, naming no path; a store that cannot be saved publishing nothing; the release report and conformance statement giving each key scope, with no key or path in the release or QC pack; and, under every preset, two runs of the synthetic collection under one project key and its store, the second with references to the first’s instances, two of its instances again, and a prior and a follow-up study of the same subject, giving the subject one Patient ID and one Patient’s Name, each source UID one replacement, so that the second run’s references resolve to the first’s instances, each value that both receive the same output, and an instance that both receive the same bytes, leaving the store unchanged, under Modified Dates moving every subject-event date by one offset, so that the other studies keep their intervals, and undertps-importkeeping the birth date that the store records, while another key gives other pseudonyms, UIDs, and offsets, and a new store another birth date.
D-005: Keyed patient pseudonyms#
Decision. Every preset replaces Patient ID and Patient’s Name with values derived from the subject’s identity (identifier and issuer, or a curator-supplied identity) under the key (D-004), rather than with empty values. One format serves every preset. It is conspicuously synthetic, deterministic under the key, valid for the VR (64 characters for LO and for each PN component group), identical for every instance of a subject, and does not embed the source identifier. The conformance statement describes it, as E.1.3 requires for dummy values.
Format. The subject’s code is the base32 form (RFC 4648) of the first 80 bits of the key’s
patientderivation of the identity. Patient ID becomesDEID-and the code (21 characters), and Patient’s Name becomesDEIDENTIFIED^and the code. An identity is either a Patient ID with its issuer, ignoring LO padding, or a curated subject identifier; the two kinds are framed differently, so the same text in each is two subjects. An empty Patient ID names no subject and needs a curated identity. Among a million subjects the chance that any two share a code is below \(10^{-12}\).Rationale. Patient’s Name is Z and Patient ID is Z/D in the Basic Profile, both of which permit a dummy value. Empty values would merge every patient in a multi-patient collection, whereas keyed pseudonyms keep subjects separate and, under a project key, consistent across runs. Conspicuous values stop a research copy from being mistaken for a clinical record.
Tests. Determinism under one key and difference across keys; VR validity; distinct pseudonyms for distinct subjects, including the same identifier from different issuers; and consistency across a subject’s instances.
D-006: Date shifting#
Decision. Where Retain Longitudinal Temporal Information with Modified Dates is selected, shift each subject’s subject-event and radiation-source dates (D-007) backwards by a whole number of weeks between 52 and 520, never zero. With a project key, the offset is read from the subject profile (D-004); with an ephemeral key, it is derived for the run. Times are unchanged. Dates found in free text are removed, not shifted. Without the option, the Basic Profile’s actions apply.
Derivation. A new subject’s offset is 52 weeks plus the first 64 bits of the key’s
date-offsetderivation of the identity, modulo 469, so each of the 469 offsets is equally likely to within one part in \(10^{16}\). A DA value moves by the offset; a DT value moves its date and keeps its time, and any UTC offset it carries becomes the nominal offset once the value is in the instance’s local time (D-007). A DT value without a full date, such as a year alone, cannot move by whole weeks, so it is not shifted, and its instance is sequestered (D-039). A DT value at a leap second, with a second of 60, is neither shifted nor converted to local time, because PS3.5 allows 60 only at a real leap second, which the moved value would not be; its instance is sequestered.Rationale. Whole weeks preserve intervals, times of day, and weekdays, which fractionation analyses need. Shifting backwards avoids future-dated plans, which planning systems may reject. Excluding zero ensures every date moves (MIDI §1.17.9). Shifting a free-text string wrongly recognised as a date can disclose the offset (MIDI §1.17.9).
Tests. Offset range and exclusion of zero; preservation of intervals, times, and weekdays; rejection of leap seconds; consistency across the studies and runs of one subject; and removal of dates in free text.
D-007: Temporal attributes by role#
Decision. L2 gives every date, time, and datetime attribute a role. Where Modified Dates is selected, each role is handled as follows:
Subject event, such as Study Date, Treatment Date, and Beam Hold Transition DateTime (300C,0127): shifted by the subject’s offset (D-006).
Radiation source, Source Strength Reference Date (300A,022C) and Time (300A,022E): shifted by the same offset, so that decay intervals to treatment remain correct.
Device, such as the calibration, installation, and manufacture attributes listed below; vocabulary version, published or local, such as Context Group Version (0008,0106) and Context Group Local Version (0008,0107); and other: replaced with a fixed, conspicuous dummy value that differs from the original.
Time zone, Timezone Offset From UTC (0008,0201): replaced with the nominal offset
+0000, after every DT value in the instance that carries its own offset is converted to the instance’s local time and given the same nominal offset. The instance’s dates and times are then all local times under one offset, so their intervals are kept, including across midnight, and no offset reveals the season of the original date through daylight saving, such as +1100 rather than +1000, or the location. The local time is the instance’s Timezone Offset From UTC where present, which PS3.3 C.12.1.1.8 makes the offset of every value without its own, and otherwise the offset of its earliest DT value that has one, compared to the microsecond. The replacement is a valid offset for the instance’s times, as C requires, and the conformance statement records that it is nominal. Intervals between instances at different offsets, such as either side of a daylight-saving change, move by the difference between their offsets. An instance with a value whose precision cannot express its conversion exactly, such as a date alone, is sequestered.
Without Modified Dates, Table E.1-1 applies unchanged. The conformance statement describes these modifications, as E.3.6 requires.
The L2 file
temporal_roles.tomlgives each DA, DT, and TM attribute of the pinned dictionary a role, including attributes that Table E.1-1 omits, such as DICONDE and DICOS attributes. It also gives a role to every attribute of another VR that Table E.1-1 cleans under Modified Dates, so a new edition that cleans another fails to load until that attribute has a reviewed rule. In 2026d it has 187 rules: 152 subject event, 2 radiation source, 12 device, 4 vocabulary version, 1 time zone, and 16 other. An attribute that PS3.3 requires to follow a subject event, such as Item Inventory DateTime (0008,0404), which must be at or after Content Date (0008,0023), is itself a subject event, so shifting keeps the order. The UI and temporal roles files share one format and loader.Besides Timezone Offset From UTC, Table E.1-1 cleans two attributes of other VRs under Modified Dates. Frame Origin Timestamp (0034,0007), each frame’s capture time as an IEEE 1588 timestamp in TAI (PS3.3 C.7.6.27.1.1), is a subject event; its seconds move by the subject’s offset, which keeps the timing between frames exactly. Certified Timestamp (0400,0310) occurs only inside the Digital Signatures Sequence (FFFA,FFFA), which Table E.1-1 removes under every option, so its role, other, never applies.
In 2026d, eleven attributes are K under Retain Device Identity and C under Modified Dates. Ten are device attributes: Date of Last Calibration (0018,1200), Time of Last Calibration (0018,1201), DateTime of Last Calibration (0018,1202), Calibration DateTime (0018,1203), Date of Manufacture (0018,1204), Date of Installation (0018,1205), Calibration Time (0014,407C), Calibration Date (0014,407E), Date of Last Detector Calibration (0018,700C), and Time of Last Detector Calibration (0018,700E). The eleventh is Beam Hold Transition DateTime. K keeps a non-Sequence value unchanged (Table E.1-1a) and E.3.8 requires retention, whereas E.3.6 requires modification, and PS3.15 defines no precedence between options. No output can satisfy both options while one of these attributes has a value, so a policy that selects both makes no conformance claim.
tps-importdoes this deliberately and handles these attributes by role, as above; any other such policy is rejected (D-011). A test fails if a regenerated Table E.1-1 adds a conflict.Rationale. E.3.6 requires every date and time in a Table E.1-1 attribute to be modified, in a manner that reduces the possibility of matching and preserves temporal relationships only to the extent the application needs. Neither removal nor retention is modification. Shifting a device or vocabulary date by the subject’s offset would disclose that offset whenever the original is known or guessable, such as a published version date or a known calibration date; MIDI §1.17.9 describes the same mechanism for free text. It would also give one device different dates in different subjects’ output, revealing the differences between their offsets. No preset needs these dates’ relationships to the images, so a fixed dummy value satisfies E.3.6 and C (a value of similar meaning that contains no identifying information) and discloses nothing.
Consequences. Dose and decay calculations stay consistent; device calibration history and vocabulary versions are lost. The first supported release ships Modified Dates, in
tps-import, inpublic-release, and in custom option sets (Scope), so its output under the option loses them. Undertps-import, Retain Device Identity keeps Source Serial Number (3008,0105), so subjects treated with the same source can be linked and the differences between their offsets disclosed; this residual risk is documented for non-clinical use.public-releasedoes not retain source serial numbers.Tests. Every temporal attribute in the pinned dictionary has a role; every date and datetime value in a Table E.1-1 attribute is modified, including one equal to the dummy value, and every time of a subject event or radiation source is kept (D-006); known device and vocabulary dates alongside shifted subject dates do not expose the offset; source-to-treatment intervals are preserved; a custom policy selecting both conflicting options is rejected; and a regenerated Table E.1-1 with a new option conflict fails the tests.
D-008: Synthetic birth dates for TPS import#
Decision.
Resolve a stable subject identity, as D-005 does.
Choose the birth date at the subject’s first export, from the instances of that run. Each study of the subject, by Study Instance UID, whose instances hold at the top level exactly one distinct Study Date that is a valid date and exactly one distinct Patient’s Age in completed years (
nnnY), padding aside, is an observation; an instance without either value adds nothing, and an age in months, weeks, or days gives no observation. The reference study is the observation with the earliest Study Date, and of those on that date the one with the least replacement Study Instance UID. The synthetic birth date is the reference study’s shifted date (D-006) minus the age in calendar years, with 29 February mapped to 28 February in a year without one, so the subject has that age, in completed years, on the shifted date.Persist the choice in the subject profile (D-004; run-only under an ephemeral key), with the reference study by its replacement Study Instance UID, its shifted date, and the age, beside the offset and derivation version, and reuse the date for every instance and later run. A study that arrives later, whatever its date, never changes the reference.
Patient’s Birth Date takes the date at the top level of the data set wherever Z or D applies to it; elsewhere, Z and D write as D-021 gives. The conformance statement describes the derivation, as E.1.3 requires for dummy values.
Failure handling. Unresolved subject identity stops the affected objects for curator resolution: the birth date edit of an instance without one stays pending, as its pseudonyms do, so it is sequestered. For an identified subject, missing or invalid reference dates or ages, or inconsistent source ages, must be resolved in the source before its first export: a study whose instances hold two different Study Dates or Patient’s Ages, or observations that no single birth date gives their ages on their dates, are inconsistent. Otherwise, where no observation can be shifted and synthesised or the ages are inconsistent, an empty birth date is written consistently for that subject, and that choice is persisted too. A conflict with an existing profile stops the subject for review: a later run that holds the reference study with another Study Date or Patient’s Age, a study whose instances disagree, or ages that no birth date reconciles with the reference’s age on its source date sequesters every instance of the subject as
birth-date-conflictand leaves the profile unchanged. A persisted empty choice is kept without these checks. Changing an exported choice requires an explicit migration of the related collection.Rationale. Patient’s Birth Date is Z in the Basic Profile, and no option retains or cleans it, so a synthetic value is a permitted dummy value. Planning systems may reject records with empty or invalid values. Recomputing the date from each study’s date and rounded age could give one subject several birth dates. The synthetic date expresses approximate age at the reference study, not the true birthday; the retained Patient’s Age remains the source for age analyses. The earliest study is the natural reference for a subject’s first export, and breaking ties by the replacement UID, which depends only on the key and the study, makes the choice independent of the order of the run. The profile records the reference by its replacement UID, never the source UID, so the store holds no identifier (D-004), and a later run recognises the reference study by the UID that it writes. Ages are compared as intervals of birth dates, each the dates that give an observation its age in completed years on its date, on the source dates, since moving a date by whole weeks does not move a year boundary with it; observations agree where the intervals meet. Completed weeks or days can straddle a birthday, so converting them to completed years is not always exact; ages in months are left out with them, so every observation comes from an age that the source states in years, and a subject whose ages are all in other units takes an empty birth date.
Tests. Several studies at one age; birthdays between studies; leap years, including a reference whose shifted date is 29 February; every synthetic date giving its age on the shifted date, and the interval comparison agreeing with a search of every candidate birth date; independence from processing order and the replacement-UID tie-break; earlier studies arriving later; missing, invalid, and inconsistent dates and ages, within a study and between studies, giving an empty date that is persisted and kept by later runs; conflicts with an existing profile sequestering every instance of the subject and no other, and leaving the profile unchanged; missing subject state leaving the edit pending; a recorded date read back after a change of derivation; the profile store’s birth dates read back, validated, and never replaced; identical birth dates across a subject’s instances and incremental runs; other presets emptying the attribute; and the statement describing the derivation only for
tps-import.
D-009: Descriptor cleaning#
Decision.
Start with a vocabulary-based cleaner, combined with context-aware checks and checks for echoes of known patient and other person identifiers, including reordered names and reformatted dates (MIDI §1.17.2).
Treat unresolved ambiguous text conservatively, subject to D-011. Remove optional attributes, use permitted empty or dummy values for required ones, or hold the output for confidential review.
Other validated methods, including removing optional descriptors, may satisfy the option. Describe the method and its limits in the conformance statement, as E.3.5 requires.
Claim Clean Descriptors (DCM 113105) only for output that retains no descriptor string that has not passed pooled human review. A descriptor that is not cleaned takes its action under the policy without the option instead, and where that action removes or replaces it, the output still meets the option, since E.3.5 specifies what the option removes, not what it retains, and E.1.1 makes Table E.1-1 the minimum actions; where that action keeps it, the output does not claim the option. A ROI Name that automatic cleaning, below, writes in the spelling of the published TG-263 vocabulary is a cleaned value (C), not a retained string, so it needs no review before the claim.
The first supported release includes the Clean Descriptors Option, in the
basic-clean-descriptorspreset. The maintainer decided on 1 October 2026 that it cleans ROI Name (3006,0026), using a vocabulary made with the TG-263 converter below, in two tiers:Automatic. A ROI Name that matches a vocabulary name once case, padding, and the separators
_,-, and space are disregarded is written in the vocabulary’s own spelling:lung l,LUNG-L, andLung Lall becomeLung_L. TG-263 writes-for a subtraction, as inLungs-PTV, so a vocabulary name that contains-matches only a name with-in the same place:lungs - ptvbecomesLungs-PTV, butLungs PTVandLungs_PTVgo to review. A name that starts with_or-also goes to review, since TG-263 marks a structure not used for dose evaluation, such as an optimisation contour, with a leading_, so_Heartis notHeart; separators elsewhere in a name are still disregarded. Only names of printable ASCII are matched, since TG-263 names are ASCII and Unicode case folding and compatibility forms would match look-alike characters. Each such rename is recorded for audit in the confidential QC material (D-016), and needs no review before the option is claimed. This applies only to the list that AAPM publishes, whose entries are generic names of anatomy and targets: a vocabulary is accepted for automatic renaming only where the digest of its entries is that of a published edition of the TG-263 spreadsheet, as PyMedPhys records it, since the converter writes AAPM’s attribution for any workbook with the TG-263 columns, including one extended with local names. A vocabulary converted from an institutional list can hold an entry that names a site or a person, such asClinicX_Lung, and its source record and digest show which list was used, not that its entries are safe to write, so every match against such a vocabulary goes to review, in the second tier, instead. As the maintainer decided on 6 October 2026, a run can be given such a list, converted as below. It renames nothing and changes no value written: a ROI Name held for review that matches one of its names, once case, padding, and separators are disregarded as above, but with any leading_or-the same in both, keeps the reason it was held for, and the confidential QC material shows its reviewer the list’s names it matched (D-016). Since the list changes no value written, the method digest does not cover it (D-024). A name also goes to review where its normalised form matches more than one vocabulary name; where the checks for echoes above find that it echoes a known patient or other person identifier; or where a different ROI Name of the same structure set would be written as the same vocabulary name, asLung_LandLUNG-Lwould, since duplicate ROI Names can make a planning system reject the import.Reviewed and remembered. Every other distinct ROI Name is listed in the confidential QC material for review. A reviewer keeps it, maps it to another name, including by a bulk rename across a collection, or has it emptied. The decisions are kept in a reviewed-names list for the site or project, held by the custodian with the key and subject profiles (D-016), and reused on later runs; this is the pooled human review that the claim above requires. A reviewer records decisions by writing them into a CSV file with the columns
roi_name,decision(keep,map, orempty), andto, which a command records in the list, starting it on first use, as the maintainer decided on 6 October 2026. Recording is all or nothing: a name given different decisions in the file, or a decision that differs from the list’s without an explicit choice to replace it, is refused and nothing is recorded, and neither its summary nor its messages quote a name or path. An instance with a ROI Name that the list does not cover and automatic cleaning does not rename is held for review (D-027), and counted by reason, without its name or any label, in the release report’sheld_for_reviewsection, rather than emptied silently, unless the user chooses explicitly to empty such names so that the run proceeds. As the maintainer decided on 6 October 2026, a held instance’s file is deleted with the staging area when the run ends, and a later run writes it once a reviewer’s decision for the name is in the list; since the current command gives each run an ephemeral key (D-004), that run’s release replaces the earlier one rather than adding to it. A decision applies to every ROI Name with exactly its spelling, once LO padding is removed, and only where automatic cleaning does not rename the name; a name sent to review only because another name of the structure set would be written the same takes the list’s decision, so mapping one of two such names lets the other be renamed. What a kept or mapped name would write is checked, as an automatic rename is, for echoes of the instance’s patient and other person identifiers and for duplicates within the structure set, ignoring case, since some planning systems compare structure names without case, and the name is held for review if either check fails, since a reviewer may have decided on it for another patient; the user’s choice to empty held names covers such a name too, so that the run proceeds. The list changes what the engine writes, so its keyed digest is an input to the method digest (D-024).
tps-importcleans ROI names in the same way and keeps no name that has not been reviewed, apart from those that automatic cleaning writes in the vocabulary’s spelling, since its output carries Patient Identity Removed YES only when every deviation from its profile and options removes or modifies more than they require (D-012).Recognising well-formed TG-263 target names by their grammar, such as
PTV_HighorCTVp_5040, which TG-263 defines by pattern rather than by list, is future development.Under Clean Descriptors, a sequence that Table E.1-1 gives C takes its Basic Profile action rather than being cleaned item by item, since rules for cleaning its contents are not designed, as the maintainer decided on 1 October 2026. In 2026d there are nine: Admitting Diagnoses Code Sequence (0008,1084), Principal Diagnosis Code Sequence (0008,1301), Primary Diagnosis Code Sequence (0008,1302), Secondary Diagnoses Code Sequence (0008,1303), Histological Diagnoses Code Sequence (0008,1304), Reason for Visit Code Sequence (0032,1067), Reason for Requested Procedure Code Sequence (0040,100A), and Request Attributes Sequence (0040,0275), which the Basic Profile removes (X), and Prescription Notes Sequence (3010,0081), which it empties (Z) and which no IOD of the first supported release uses.
Under Clean Descriptors, every other attribute to which the policy gives C, such as Study Description, Series Description, and Beam Name, takes the action that the policy gives it without that option, unless descriptor cleaning writes it as the next bullet describes, and an instance in which that action removes or replaces each such attribute still claims the option, since E.3.5 specifies what the option removes and Table E.1-1 gives the minimum actions, as the maintainer decided on 6 October 2026, over leaving the option unclaimed for such output or cleaning short labels too. An instance in which that action keeps such an attribute does not claim the option. A preset’s policy without the option is composed from its other options as the preset composes them, so under
tps-importthe eleven device dates and times on which Retain Device Identity and Modified Dates conflict are modified by their role there too (D-007), where a custom option set of the same options would be refused; a custom option set’s is composed as a custom option set. The conformance statement gives that action for each such attribute, at each place.Reviewers’ decisions on the values of those other descriptors are kept in a reviewed descriptors list for the site or project, beside the reviewed-names list and held by the custodian in the same way. A decision keeps, maps, or empties one value of one attribute, by its tag and exact spelling once padding is removed, wherever that attribute holds it; each value of an attribute whose VR allows several is decided on alone. The attributes are those that Table E.1-1, or a reviewed rule for text that it omits (D-022), gives C under Clean Descriptors, of VR SH, LO, ST, LT, UC, or UT, other than ROI Name, and the five attributes of free text that Table E.1-1 gives C under Retain Patient Characteristics, two of which, Pre-Medication (0040,0012) and Special Needs (0038,0050), Clean Descriptors does not clean (D-038); in 2026d there are 192. Under Retain Safe Private, the list also decides on the private text that a safe private rule retains, each attribute named by its private creator, group, element within the block, and VR, written
(gggg,"CREATOR",ee) VR, as(0019,"GEMS_ACQU_01",9E) LO, since its tag depends on the block that its creator reserves (D-035); the list’s format ispymedphys-deid-reviewed-descriptors/3, which a list of format 2, without Pre-Medication or Special Needs, or of format 1, without private text either, is read as. A value to map to is printable ASCII that the attribute’s VR can hold. What a kept or mapped value would write is checked for echoes of the instance’s patient and other person identifiers, as for ROI names, and also for a whole identifier or a word of one, of at least four letters and digits, among the value’s letters and digits, since free text can run an identifier into other text or reformat it, asMRN 99-1234does991234; a value that echoes one, or that the list does not cover and the automatic tier below does not keep, is not cleaned. A reviewer records decisions by writing them into a CSV file with the columnsattribute(a keyword, a tag, or a private attribute’s key, as the QC pack gives it),value,decision, andto, which a command records in the list as the ROI-name command does, run aspython -m pymedphys._dicom.deidentify.reviewed_descriptors_command. A run is given the list as the reviewed-names list is, and applies it to each such descriptor whose decoded value the edits collected in the VR that the data dictionary gives it, each value of a VR that allows several split at its backslashes. It writes an element with what cleaning gives its values only where every value is cleaned, at least one is written with text, and no kept value is written beside one that a reviewer mapped or emptied, since the residual search leaves out the element of a kept value as a retained value (D-027), which would leave out that value’s source too. An instance withheld before its descriptors are cleaned is still edited so that its values are collected for its subject’s search (D-027), and each descriptor that cleaning would write with a kept value is left out of that collection in the same way, so that the same value written in the rest of its series or study is not found from it; a value that a reviewer maps or empties, that is not cleaned, or that echoes an identifier stays in the search, and so does a kept value in a sequence that also holds an attribute given C that cleaning would not write, since that attribute’s action without the option may remove the sequence with both (D-020), which only an instance that is written settles. A descriptor of an information entity that spans instances, one that a module of the instance’s IOD in the pinned PS3.3 defines at the top level for the Patient, Study, Series, or Frame of Reference entity, such as Series Description, Protocol Name, or Study Description, describes the entity, so its instances hold it alike, as dcentvfy checks. Cleaning decides on each instance’s values with that instance’s own identifiers, so the instances of a series whose values differ, as where text was added to some of them, or one of which names a person whose name is a word of the value, would otherwise write it in some instances and remove it from others. Before writing any instance, a run therefore finds what cleaning would write for each such descriptor of each instance, by the same rules, and writes it only where every instance of its patient, study, series, or frame of reference in the run, as Patient ID with Issuer of Patient ID and the Study Instance, Series Instance, and Frame of Reference UIDs name them, would write the same values; otherwise every instance of the entity takes the action without the option, as for a descriptor that is not cleaned. An instance without the attribute counts as one that writes other values, an instance that the run sequesters before cleaning is left out, and one that cannot be prepared counts as one that does not write it. A kept value that is not written only because its entity disagrees stays out of the residual search, as it would where written, while a mapped value’s source and a value held in its own instance stay in it. An attribute that another option’s cleaner leaves to the list is decided on in each instance alone, since a held value there holds its instance rather than falling back. A descriptor that another selected option’s cleaner cleans is left to that cleaner, unless the cleaner leaves the values that it cannot clean to the list, as Retain Patient Characteristics’ cleaner does its free text (D-038). Each such value is given the list’s decision alone, never the automatic tier’s, and checked for echoes in the same way; the element is written with what the list gives where every value is cleaned and no kept value is beside a mapped or emptied one, with no value where none has text. Its action without Clean Descriptors is that option’s C, which cannot remove a value that the option keeps, so an element with a value that is not cleaned is written empty in the staged file, which is not released, and holds its instance for review, as a ROI Name does, and no user’s choice empties it instead; one with a kept value beside a mapped or emptied one sequesters its instance. Every other such element, including one whose sequence another attribute’s action removes, takes the action that the policy gives it without the option, as the previous bullet describes, so a value that is not cleaned is removed or replaced rather than released, and the instance is not held for it. The maintainer decided on 13 October 2026 that such a value is removed or replaced in this way, over holding the instance until a reviewer decides on the value, which would hold nearly every instance of a first run, since Study Description and other free text are on almost every file and the automatic tier covers only the technique descriptors (D-036); under both, a value that is not cleaned is never released. The confidential QC pack lists each element’s values, what cleaning decided for each, and whether it was written, so that a reviewer can record decisions for later runs (D-016), and the release report counts the values by outcome, the distinct values not cleaned by reason, and the elements that took the action without the option, an element that held its instance not among them, and counts the instances held for a value of another option’s attribute at the stagedescriptors, naming none. The list changes what the engine writes, so its keyed digest, in a derivation domain of its own,reviewed-descriptors, is an input to the method digest (D-024).For technique descriptors, an automatic tier also keeps, without review, a value made only of reviewed vocabulary words, where the list has no decision on it (D-036). This is the one departure from the rule above that a retained descriptor string has passed pooled human review.
PyMedPhys downloads the published TG-263 spreadsheet itself and uses it as the default vocabulary, as the maintainer decided on 2 October 2026; it bundles no copy. The edition it uses is pinned in PyMedPhys by its URL on AAPM’s Radiation Oncology Nomenclature Resource Page, the SHA-256 of the file, and the digest of its entries; the pin is the 2017-08-15 edition. The download is cached in the PyMedPhys data directory and used only if it has the pinned SHA-256, and a file that does not is refused. A user without internet access can convert a copy obtained elsewhere, which is checked against the pin in the same way. A monthly check, like the check for a new DICOM edition, opens an issue when AAPM’s page links to a download that maintainers have not reviewed, no longer links to the pinned spreadsheet, or the pinned file has changed, so that moving to a new edition is a reviewed change to the pin, never automatic.
A vocabulary is a UTF-8 JSON file that holds its entries together with their source, version, source-file SHA-256, and required attribution. A converter command produces it from the TG-263 spreadsheet, or from an institutional list exported as CSV with a
Namecolumn, as the maintainer decided on 1 October 2026, and converted files are never edited by hand. The converter commands are kept out of thepymedphyscommand line until the tool is released, as the maintainer decided on 2 October 2026, as is every other command of the tool, and until then run aspython -m pymedphys._nomenclature, the command that records reviewers’ decisions aspython -m pymedphys._dicom.deidentify.reviewed_names_command, and the command that records a QC reviewer’s attestation aspython -m pymedphys._dicom.deidentify.attestation_command; a test fails if apymedphyscommand outside the maintainers’ ownpymedphys devcommands belongs to the tool. Releasing the tool makes them public commands with user documentation, in the pull request of the first supported release (M6), as the maintainer decided on 6 October 2026. Without a vocabulary, no ROI Name is renamed automatically: each needs a reviewer’s decision from the reviewed-names list, or is held for review.pymedphys._nomenclature.tg263converts the TG-263 spreadsheet. It reads the downloaded or a local copy, maps its columns by header text, and writes JSON with the spreadsheet’s file name, worksheet version, SHA-256, AAPM’s attribution, and a digest of its entries; its loader rejects a file whose entries no longer match that digest. Entries are kept as published, except that surrounding whitespace is removed, the derived “N Characters” column is dropped, and unlabelled columns are ignored. The module sits outside the de-identification package so that other tools, such as a check of structure names against TG-263, can use it.
Rationale. E.3.5 specifies what to remove, not an algorithm (Note 4). A vocabulary can contain words that are also names, such as “Hand” (MIDI §1.17.2), so a word’s presence in a vocabulary is not evidence that its use within free text is safe. JSON keeps the provenance, attribution, and value types in the same file as the entries, which CSV cannot, and matches the repository’s existing data files. The TG-263 journal article is licensed CC BY-NC-ND 4.0, which forbids the commercial use and adaptation that Apache-2.0 permits, and no licence compatible with Apache-2.0 has been found for its nomenclature spreadsheet, so, under the packaging rule for bundled data in
AGENTS.md, PyMedPhys downloads the published file from AAPM when it is needed rather than bundling one. Pinning the file’s SHA-256 and the digest of its entries makes the default vocabulary reproducible and detects a changed or substituted file; a hash taken from a third-party mirror was rejected, since it would show only what the mirror holds. AAPM publishes the spreadsheet in the Excel 97-2003 format, whichxlrdreads. Under the Basic Profile alone, ROI Name is Z, ROI Observation Label and Beam Description are X, and RT Plan Label is D, so a first release with the Basic Profile alone would produce RT Structure Sets without usable structure names, which are of limited use for radiotherapy research. Including the option is a real increase in scope, with review risk, because Clean Descriptors applies to every descriptor, such as Study Description and Series Description, not only to ROI names. Writing the vocabulary’s spelling of a ROI name that matches it once case, whitespace, and separators are disregarded is cleaning as Table E.1-1a defines C, replacing the value “with values of similar meaning known not to contain identifying information”, since the whole value written is a vocabulary entry. The caution about “Hand” (MIDI §1.17.2; PS3.15 E.3.5 Note 2) concerns words found inside free text, such as a Study Description, and matching a whole ROI Name never yields such a word:Dr Handnever normalises toHand. Echoes of known patient and other person identifiers are still checked, and the safety of the vocabulary’s own entries rests on its source, which is why only a published edition’s entries are renamed automatically. Matching only exact spellings was rejected because it would empty structure names that differ from TG-263 only in case or separators. A name whose normalised form matches several vocabulary names cannot be renamed without a choice, so a reviewer makes it. Remembering reviewed decisions for a site or project means that each distinct name is reviewed once, and holding an instance whose name nobody has reviewed, rather than emptying the name silently, keeps names that a reviewer would keep; a user who cannot wait for review can choose to empty them. TG-263 target names are defined by pattern, so no list holds them all. Cleaning a sequence means changing the values within it where the meaning of the sequence in the IOD is specified, or applying the Profile’s rules to each of its items otherwise (Table E.1-1a); neither is designed for the codes of diagnoses and reasons or for the contents of Request Attributes Sequence, so their Basic Profile action applies.Tests. A ROI name that matches a vocabulary name once case, whitespace, and the separators
_,-, and space are disregarded is written in the vocabulary’s spelling, and the rename is recorded in the confidential QC material; a name whose normalised form matches more than one vocabulary name, a name that echoes a known patient or other person identifier, and different ROI names of one structure set that would be written as the same vocabulary name, such asLung_LandLUNG-L, go to review, as does every match against a vocabulary converted from an institutional list, which, given to a run, writes no name and shows the reviewer of a held name the list’s names it matched; reviewed decisions to keep, map, or empty a name, including a bulk rename across a collection, are reused on later runs, apply only to the exact spelling, and are held where what they would write echoes an identifier or duplicates another name of the structure set; decisions recorded from a reviewer’s CSV file start the list on first use and are added to it later, a decision that differs from the list’s is refused unless replaced explicitly, and a malformed file, a name given different decisions, or a list in a protected location records nothing, with messages that quote no name or path; the list’s keyed digest is the same for the same decisions under the same key, whatever order they were recorded in, and changes with any decision, name, or key; an instance with a ROI name that the reviewed-names list does not cover and automatic cleaning does not rename is held in the staging area, or written with that name emptied where the user has chosen so explicitly;tps-importkeeps no name that has not been reviewed, apart from those that automatic cleaning writes in the vocabulary’s spelling; each sequence that Table E.1-1 gives C under Clean Descriptors takes its Basic Profile action; names that overlap anatomical terms; clinician names; mixed descriptive and identifying text; non-English text; missing source identifiers; converting the AAPM spreadsheet and an institutional list; downloading the pinned edition, and refusing a file that does not match the pin; refusing automatic renaming with any vocabulary whose entries are not those of a published edition; matching a hyphen in a vocabulary name only with a hyphen; sending a name with a leading_or-to review; rejecting a vocabulary without its source record; and processing without one. Output that retains a descriptor string that has not passed pooled human review never claims the option, and output whose other descriptors take their Basic Profile actions, which remove or replace them, claims it, as an RT Plan whose Type 1 RT Plan Label is given a dummy value does; a vocabulary word found within free text never on its own lets a descriptor be retained; and output whose ROI names are all automatic renames claims the option without review. Reviewed decisions on other descriptor values apply to one attribute and one exact value, each value of a multi-valued attribute alone, and are reused on later runs; the list holds only the descriptors that Clean Descriptors cleans and mappings that their VRs can hold, and is refused in a protected location, malformed, or with a repeated value, with messages that quote no value or path; a value that the list does not cover, or whose kept or mapped value echoes an identifier by word, as a whole, or within its letters and digits, is held, or emptied where the library’s caller asks, which no run does; a run writes a descriptor whose values are all kept, mapped, or emptied by the list or kept by the technique vocabulary, leaves its kept values out of the residual search, and lists them as retained strings, while a descriptor with a value not cleaned, with only empty values, with a kept value beside a mapped or emptied one, or read in another VR takes the action without the option and still claims the option where that action removes or replaces it; each value of a multi-valued descriptor is cleaned alone; in a run, a Series Description or Study Description is written in every instance of its series or study where every instance would write the same value, and removed from every one where one instance’s value differs, where one instance names a person whose name is a word of it, or where one instance has none, while another series of the subject keeps its own and a value removed only for that reason is not searched for in it; an instance that the run did not prepare writes such a descriptor only where it agrees with its entity’s prepared instances, or alone where its entity has none; the QC pack lists each descriptor’s values, outcomes, and whether it was written, and the release report counts them without values; and the list’s keyed digest, in a derivation domain of its own, is the same for the same decisions under the same key and changes with any decision, value, attribute, or key. An instance withheld before cleaning leaves out of its collected values a Series Description that the vocabulary keeps, but not a Study Description that echoes the patient, a Protocol Name that a reviewer empties, or an Admitting Diagnoses Description that a reviewer maps, and under the Basic Profile alone leaves out none; nor does it leave out a value that is not cleaned, a vocabulary value that echoes the patient’s name, or a kept value beside a mapped one in one element, while it leaves out, whole, an LT value with a backslash that a reviewer keeps, listing it among the QC pack’s drops as retained; a kept Series Description in an RT Structure Set’s Source Series Information Sequence stays in its collected values where another item’s Series Description is not cleaned, as it is removed with the sequence from an instance that is written, and is left out where every item’s is kept; and with Retain Patient Characteristics, a value of Allergies that a reviewer keeps beside one that a reviewer maps sequesters its instance, which still collects that element’s values for its subject’s search but leaves out a Patient State that a reviewer keeps; and its kept Series Description does not hold another slice of its series. Every preset with Clean Descriptors has a policy without it, from which the engine builds the rules that descriptors fall back to and which the conformance statement describes, andtps-import’s modifies the eleven device dates and times as the preset does, while the same options as a custom option set are refused; and the synthetic collection run undertps-importreleases every instance but those withheld under the Basic Profile, with its ROI Names cleaned, its kept rows kept, its device dates modified, and no CID 7050 code.
D-010: Unsupported object types#
Decision. Sequester Structured Reports other than those of the supported IODs below, Presentation States other than the softcopy ones below, instances of Private SOP Classes, and objects outside the supported scope. List them in the report and exclude them from the conformance claim. An instance is classified from its SOP Class UID, through PS3.4 Table B.5-1, and from its file’s transfer syntax. Support is decided by IOD, so every Storage SOP Class that Table B.5-1 maps to a supported IOD is supported. The first supported release de-identifies instances of 61 IODs in the Implicit VR Little Endian and Explicit VR Little Endian transfer syntaxes and in the twelve transfer syntaxes that encapsulate Pixel Data that pydicom 3.0.2’s decoding plugins decode (Architecture item 2): CT Image, Enhanced CT Image, Legacy Converted Enhanced CT Image, MR Image, Enhanced MR Image, Enhanced MR Color Image, Legacy Converted Enhanced MR Image, MR Spectroscopy, Positron Emission Tomography Image, Enhanced PET Image, Legacy Converted Enhanced PET Image, Nuclear Medicine Image, RT Structure Set, RT Plan, RT Dose, RT Image, Enhanced RT Image, Enhanced Continuous RT Image, RT Segment Annotation, RT Radiation Set, C-Arm Photon-Electron Radiation, Tomotherapeutic Radiation, Robotic-Arm Radiation, RT Beams Delivery Instruction, RT Brachy Application Setup Delivery Instruction, RT Radiation Set Delivery Instruction, RT Beams Treatment Record, RT Ion Plan, RT Ion Beams Treatment Record, RT Brachy Treatment Record, RT Treatment Summary Record, Spatial Registration, Deformable Spatial Registration, Segmentation, Surface Segmentation, X-Ray Radiation Dose SR, Enhanced X-Ray Radiation Dose SR, Radiopharmaceutical Radiation Dose SR, Patient Radiation Dose SR, Basic Text SR, Enhanced SR, Comprehensive SR, Comprehensive 3D SR, Extensible SR, Key Object Selection Document, Mammography CAD SR, Chest CAD SR, Colon CAD SR, Procedure Log, Spectacle Prescription Report, Macular Grid Thickness and Volume Report, Waveform Annotation SR, Parametric Map, Real World Value Mapping, Grayscale Softcopy Presentation State, Color Softcopy Presentation State, Pseudo-Color Softcopy Presentation State, Blending Softcopy Presentation State, XA/XRF Grayscale Softcopy Presentation State, Variable Modality LUT Softcopy Presentation State, and Encapsulated PDF. The For Processing SOP Classes, such as CT Image Storage - For Processing (1.2.840.10008.5.1.4.1.1.2.3) and Enhanced CT Image Storage - For Processing (1.2.840.10008.5.1.4.1.1.2.4), are among them, since Table B.5-1 maps each to its IOD. The maintainer decided on 7 October 2026 to bring MR and PET, including their enhanced variants, and Enhanced CT into the first supported release, which had covered CT Image, RT Structure Set, RT Plan, and RT Dose. That adds ten IODs: every IOD of a CT, MR, or PET image Storage SOP Class in Table B.5-1, and MR Spectroscopy. On 25 October 2026 the maintainer also decided to bring RT Beams Treatment Record, RT Image, Spatial Registration, Deformable Spatial Registration, and Segmentation into the first supported release, “so long as this is an expansion of scope”. Their text, UID, and date attributes were reviewed ahead of supporting them (D-022), and each is supported in a change of its own, which settles where its plain X and its D sequester an instance (D-020, D-021). RT Beams Treatment Record, RT Image, Spatial Registration, Deformable Spatial Registration, and Segmentation are supported, which adds five IODs. The same day the maintainer added radiation dose reports, and then every other Structured Report IOD, to the target coverage; the X-Ray Radiation Dose SR and Radiopharmaceutical Radiation Dose SR are supported, which adds two IODs; the Basic Text SR, Enhanced SR, Comprehensive SR, Comprehensive 3D SR, and Extensible SR, which add five more and use no attribute and no reference site that the dose reports do not; and the Enhanced X-Ray Radiation Dose SR and Patient Radiation Dose SR, which add two more, and whose attributes were reviewed with the other two dose reports’ ahead of supporting them (D-022). The Key Object Selection Document, Mammography CAD SR, Chest CAD SR, Colon CAD SR, Procedure Log, Spectacle Prescription Report, Macular Grid Thickness and Volume Report, and Waveform Annotation SR are supported too, which adds eight more. A Key Object Selection Document is not a Structured Report by its IOD’s name, but its content tree is in the same Content Sequence, built from the same content items, so it is supported, cleaned, and claimed as a report is. These eight, and the other Structured Report IODs, use no attribute that the reviewed IODs do not (D-022): their IODs add the Key Object Document, Synchronization, Enhanced General Equipment, and Timezone Modules, whose attributes the reviewed IODs already use, and none of them defines Waveform Annotation Sequence (0040,B020) or Common Instance Reference. The others are sequestered, as above, until each is supported. Rendition Selection Document is among PS3.3’s Structured Report IODs but has no Storage SOP Class in the pinned Table B.5-1, so no instance is classified as one, and a SOP Class UID that names it would be sequestered as not a Standard Storage SOP Class. A Procedure Log orders its entries by increasing Observation DateTime (0040,A032) (PS3.3 Section A.35.7.3.1.2), which D would give one constant, so under a policy that neither keeps nor modifies that datetime each entry takes the dummy datetime of its rank (D-021), and a log whose entries are not in that order is sequestered (D-047). On 31 October 2026 the maintainer brought the 22 other RT IODs of Table B.5-1 into the first supported release, in this order: RT Ion Plan and RT Ion Beams Treatment Record; RT Brachy Treatment Record and RT Treatment Summary Record; Enhanced RT Image and Enhanced Continuous RT Image; and the 16 second-generation RT IODs, RT Physician Intent, RT Segment Annotation, RT Radiation Set, RT Radiation Record Set, RT Radiation Salvage Record, RT Treatment Preparation, RT Patient Position Acquisition Instruction, RT Beams Delivery Instruction, RT Brachy Application Setup Delivery Instruction, RT Radiation Set Delivery Instruction, and the C-Arm Photon-Electron, Tomotherapeutic, and Robotic-Arm Radiation IODs and their Records. As for the IODs added on 25 October, each one’s text, UID, and date attributes are reviewed ahead of supporting it (D-022), and each is supported in a change of its own, which settles where its plain X and its D sequester an instance (D-020, D-021); until then each is sequestered. RT Ion Plan and RT Ion Beams Treatment Record are supported, which adds two IODs. An RT Ion Plan describes a treatment with beams of protons or heavier ions, and an RT Ion Beams Treatment Record what was delivered of one; neither holds pixel data, so neither can show a face or hold burned-in text. An RT Ion Plan names its structure set, its RT Doses, and the plans related to it, in Referenced Structure Set Sequence (300C,0060), Referenced Dose Sequence (300C,0080), and Referenced RT Plan Sequence (300C,0002), and an RT Ion Beams Treatment Record names the plan that it records in Referenced RT Plan Sequence, by UIDs that the run’s key replaces as it replaces the referenced instances’ own (D-003), so a written record still names the written plan. Their text that Table E.1-1 omits has rules reviewed ahead of supporting them (D-022), and they add no place where the Basic Profile’s actions sequester an instance beyond those that RT Plan and RT Beams Treatment Record have: Responsible Person and Responsible Organization in the Patient Module (D-020). The Institution Code Sequence of the person who resolved an interlock, here in Treatment Session Ion Beam Sequence (3008,0021), takes the reviewed dummy item that it takes in an RT Beams Treatment Record (D-021). RT Brachy Treatment Record and RT Treatment Summary Record are supported, which adds two IODs. An RT Brachy Treatment Record says what an afterloader or a manual loading delivered in one session, through each channel of each application setup of a brachytherapy plan, and an RT Treatment Summary Record totals what has been delivered of a course so far; neither holds pixel data, so neither can show a face or hold burned-in text. Each names the plan that it records in Referenced RT Plan Sequence (300C,0002), and the treatment records related to it in Referenced Treatment Record Sequence (3008,0030), by UIDs that the run’s key replaces as it replaces the referenced instances’ own (D-003), so a written record still names the written plan and records. Their attributes were reviewed ahead of supporting them (D-022), and they add one place where the Basic Profile’s actions would sequester an instance beyond those that RT Plan and RT Beams Treatment Record have: Source Manufacturer (300A,0216), which Table E.1-1 gives X, is Type 2 in Recorded Source Sequence (3008,0100), which is Type 1 at the top level of RT Brachy Treatment Record, so every conforming record holds it and no Type 3 sequence encloses it. A plain X there would sequester every RT Brachy Treatment Record under
basic,basic-clean-descriptors, andpublic-release, so it is emptied there instead, as Requested Procedure ID is in a Structured Report’s Referenced Request Sequence (D-020). Beyond that, they add no place that sequesters: Responsible Person and Responsible Organization in the Patient Module (D-020) sequester as in every IOD, and RT Brachy Treatment Record has no interlock, so it holds no Institution Code Sequence for the person who resolved one. Enhanced RT Image and Enhanced Continuous RT Image are supported, which adds two IODs. Each holds projection images made before, during, or after a treatment session, acquired directly, such as a kV or MV image of the patient in the treatment position, or derived from a volume such as a CT, as a digitally reconstructed radiograph is (PS3.3 Sections A.86.1.15.1 and A.86.1.16.1); an Enhanced Continuous RT Image holds frames acquired at a high frame rate, of which its Selected Frame Functional Groups Sequence (3002,0101) describes a selection (PS3.3 Section C.7.6.29). Each is therefore treated as an RT Image is: the QC pack lists its series as able to show a face in profile, whatever its Image Type, gantry angle, or Number of Frames, and as showing the head or neck where its attributes name a region of it, for review through the series’ previews, and one whose Image Type has a second value of SECONDARY is also listed as able to hold burned-in text (D-015, D-017). Its pixel data are cleaned, reviewed, and claimed under the Clean Pixel Data and Clean Recognizable Visual Features Options as any other image’s are (D-037, D-046). Neither IOD defines Burned In Annotation (0028,0301) or Recognizable Visual Features (0028,0302), so an instance that claims either option gains the attribute as a standard attribute of a Standard Extended SOP Class, as an RT Plan does. PS3.3 Sections A.86.1.15.4.2 and A.86.1.16.4.2 forbid the General Image Module, which defines both, in a Standard Extended SOP Class of these IODs; the engine adds the two attributes alone, which PS3.15 E.3.1 and E.3.2 require, and none of the module’s others. It names the instances that it relates to, such as the RT Plan, RT Radiation Set, or RT Radiation of the treatment that its frames image, and the images that it was derived from, by UIDs that the run’s key replaces as it replaces the referenced instances’ own (D-003), so a written image still names the written instances. Its Series Number is Type 1 in the Enhanced RT Series Module, so it takes its rank, as in a Segmentation (D-022). Their attributes were reviewed with their support (D-022): one text attribute that Table E.1-1 omits, Conceptual Volume Combination Expression (3010,000C), needed a rule, and they add no place where the Basic Profile’s actions sequester an instance beyond those that the IODs supported before them have. Responsible Person and Responsible Organization in the Patient Module sequester as in every IOD (D-020), and the Person Identification Code Sequence in the Author Identification Sequence (3010,0019) of the Radiotherapy Common Instance Module takes the reviewed dummy item that it takes wherever Table E.1-1 gives it D (D-021). RT Segment Annotation, RT Radiation Set, and the C-Arm Photon-Electron, Tomotherapeutic, and Robotic-Arm Radiation IODs are supported, which adds five IODs. Their attributes were reviewed ahead of supporting them, with those of the other 11 second-generation RT IODs (D-022), and of the places where that review found that the Basic Profile’s actions would sequester an instance, only one is in them: RT Accessory Holder Slot ID (300A,0611), which Table E.1-1 gives Z, is Type 1 in RT Accessory Holder Slot Sequence (300A,0610) of C-Arm Photon-Electron Radiation and Robotic-Arm Radiation, where it takes the dummy value (D-020). RT Beams Delivery Instruction, RT Brachy Application Setup Delivery Instruction, and RT Radiation Set Delivery Instruction are supported, which adds three IODs. A delivery instruction tells a treatment delivery system what to deliver in a session: the RT Beams Delivery Instruction which beams of an RT Plan, the RT Brachy Application Setup Delivery Instruction which application setups of an RT Plan, and the RT Radiation Set Delivery Instruction which radiations of an RT Radiation Set. None holds pixel data, so none can show a face or hold burned-in text. They name the plan in Referenced RT Plan Sequence (300C,0002), the treatment record of the session that an instruction continues in Referenced Treatment Record Sequence (3008,0030), the radiation set in Referenced RT Radiation Set Sequence (300A,0702), and its radiations to deliver or omit in Referenced RT Radiation Sequence (300A,0630), by UIDs that the run’s key replaces as it replaces the referenced instances’ own (D-003), so a written instruction still names the written plan, record, radiation set, and radiations. Their attributes were reviewed ahead of supporting them (D-022), and they add no place where the Basic Profile’s actions sequester an instance: Responsible Person and Responsible Organization in the Patient Module (D-020) sequester as in every IOD, and the RT Radiation Set Delivery Instruction’s sequences that resolve to D take the items that reviewed rules give them elsewhere, the dummy Person Identification Code Sequence item of an author or of an omitted radiation’s asserter, and the keyed item of Referenced Performed Procedure Step Sequence (D-021). The RT Radiation Set Delivery Instruction’s Series Number is Type 1 in its Enhanced RT Series Module, so it takes its rank, as in a Segmentation (D-022). A report’s content tree is in Content Sequence (0040,A730), which the Basic Profile gives D, and a sequence has no dummy value (D-021), so a report is released only under a policy whose Clean Structured Content keeps its tree (D-047). A registration’s frames of reference, including a deformable registration’s Source Frame of Reference UID (0064,0003), and the images it registers are named by UIDs that the run’s key replaces as it replaces the registered instances’ own (D-003), so a written registration still ties the written images to their frames of reference; its matrices and deformation grids identify no one and are kept. An RT Image is a projection, such as a portal image, a simulator radiograph, or a digitally reconstructed radiograph, so a lateral one can show the face in profile: the QC pack lists every RT Image’s series as able to show a face, whatever its Image Type, for review through the series’ previews, and an RT Image that holds Conversion Type (0008,0064), which its IOD makes Type 2, or an Image Type whose second value is SECONDARY, is also listed as able to hold burned-in text and previewed at full resolution (D-015, D-017). Its pixel data are cleaned, reviewed, and claimed under the Clean Pixel Data and Clean Recognizable Visual Features Options as any other image’s are (D-037, D-046). It names the plan that it was made for, in Referenced RT Plan Sequence (300C,0002), by a UID that the run’s key replaces as it replaces the plan’s own (D-003), so a written RT Image still names the written plan. Its text that Table E.1-1 omits has rules reviewed ahead of supporting it (D-022), and it adds no place where the Basic Profile’s actions sequester an instance beyond those that CT Image has (D-020, D-021). Segmentation Storage and Label Map Segmentation Storage are both supported, since Table B.5-1 maps both to the Segmentation IOD, while Height Map Segmentation, which it maps to an IOD of its own, is not. A Segmentation’s frames are masks of its segments, and a segment of the skin or body traces the patient’s surface, as an outline’s contours do, whatever its label: the QC pack lists every Segmentation as able to show a face, and shows eachBINARYorLABELMAPone, as written, on a segments sheet (D-015, D-017). It claims the Clean Recognizable Visual Features Option only on a verdict given on that sheet, since the pack records the SHA-256 of its written pixel data only where the sheet shows every frame, and in a defaced CT series’ frame its segments are cleared in the face block, less the kept brain, before the reviewer sees them (D-046, D-052). Its pixel data are cleaned and claimed under the Clean Pixel Data Option as any other image’s are, so aBINARYone, whose pixels are single bits rather than whole bytes, is sequestered under that option asuncleanable-pixel-data(D-037). It names the series and images that it segments, in Referenced Series Sequence (0008,1115) and in its frames’ Derivation Image functional groups, by UIDs that the run’s key replaces as it replaces theirs (D-003), so a written Segmentation still names the written images. Its text that Table E.1-1 omits, such as Segment Label (0062,0005), has rules reviewed ahead of supporting it (D-022), and the places where the Basic Profile’s actions sequester it are those of CT Image, Responsible Person, Responsible Organization, and Pixel Data Provider URL (0028,7FE0), which is present only with a JPIP transfer syntax, which the engine does not read, and, in aPALETTE COLORlabel map, an ICC Profile that is not an RGB profile, as in the enhanced IODs (D-020, D-021). Its Series Number is Type 1, so it takes its rank, as in a Structured Report (D-022), and its Tracking UID (0062,0021), which identifies a finding tracked across instances rather than referencing one, is replaced by the run’s key (D-003). On 31 October 2026 the maintainer also brought the other IODs that RT exports carry into the first supported release, “All of them, each with evidence”: Surface Segmentation; Computed Radiography and Digital X-Ray; Nuclear Medicine; Parametric Map and Real World Value Mapping; the Secondary Capture IODs; the Presentation States; and Encapsulated PDF. Each family is supported in a change of its own, with its own evidence, and until then each is sequestered. Surface Segmentation, Parametric Map, and Real World Value Mapping are supported, which adds three IODs. A Surface Segmentation holds no pixel data: its segments are meshes, whose Point Coordinates Data (0066,0016) place each point in the patient, so a mesh of the skin or the body traces the face as an outline’s contours do, whatever its segment’s label or code says. No preview of the QC pack draws a mesh yet, so under Clean Recognizable Visual Features every Surface Segmentation, and any other instance that holds a Surface Sequence (0066,0002), is held for review asno-face-verdictwhatever its verdict, and never released under that option, as a deformable registration’s grid was before its sheets (D-017, D-046); without the option, the Basic Profile claims nothing about a face, and its meshes are kept, as an RT Structure Set’s contours are. It names the series and images that its surfaces were generated from, in Segment Surface Source Instance Sequence (0066,002E) and the Common Instance Reference Module, by UIDs that the run’s key replaces as it replaces theirs (D-003), so a written Surface Segmentation still names the written images. Its text that Table E.1-1 omits, Surface Comments (0066,0004) and Surface Processing Description (0066,000B), has rules reviewed ahead of supporting it: each is typed text, removed by Type and cleaned under Clean Descriptors, as Image Comments and Derivation Description are, and its segments’ labels, descriptions, and algorithm names have the Segmentation IOD’s rules (D-022). It shares the Segmentation Series Module, so its Series Number is Type 1 and takes its rank, and its Tracking UID is replaced by the run’s key, as a Segmentation’s are; it adds no place where the Basic Profile’s actions sequester an instance beyond those that CT Image has, Responsible Person and Responsible Organization (D-020, D-021). A Parametric Map’s frames hold a quantity derived from images of the patient, such as an apparent diffusion coefficient or a standardised uptake value, as integers in Pixel Data or as floating-point values in Float Pixel Data (7FE0,0008) or Double Float Pixel Data (7FE0,0009) (PS3.3 Section A.75), placed by its functional groups as an enhanced image’s frames are. A map of the head shows its outline wherever the quantity differs from the air around it, whatever the quantity, so the QC pack lists every Parametric Map as able to show a face, whatever its Number of Frames, and one whose attributes name the head or neck as showing it (D-015, D-017). Its integer pixel data are cleaned, previewed, reviewed, and claimed under the Clean Pixel Data and Clean Recognizable Visual Features Options as an enhanced MR image’s are (D-037, D-046). Both options read floating-point pixel data: Clean Pixel Data searches each frame and blacks out its text in the element that held it (D-037), and the QC pack previews it, so that a face verdict on its previews releases it under Clean Recognizable Visual Features (D-017, D-046); under a policy with neither option its pixel data are written as received, as every image’s are. A development check,pymedphys._dicom.deidentify.parametric_map_check, which only a GitHub-hosted runner of thePixel Options on IDC Parametric Mapsworkflow (.github/workflows/parametric-map-check-idc.yml), started by hand, runs on real data, gives both options the 691 floating-point Parametric Maps of thetcga_gbm360analysis results in NCI’s Imaging Data Commons (collection TCGA-GBM, doi:10.5281/zenodo.17470190, CC BY 4.0, which the maintainer allowed on 1 November 2026 for public data whose licence explicitly permits its use), selected from the index thattext_evaluation_idcpins and refused unless their files’ SHA-256s hash to the one it pins, and counts, under Clean Pixel Data, each outcome, whether each map is written in its own element with its data type and shape, and the regions blacked out, and, under Clean Recognizable Visual Features, whether each is held without a verdict, previewed and shown whole, and released on a face verdict of absent bound to its written pixel data. Its summary, labelledpymedphys-deid-parametric-map-check/1, and its page give only counts, codes, digests, versions, the text finder’s method, and the data set’s public identifiers. The maps are pathology-derived AI maps of glioblastoma, not head images, so they show the options working on real floating-point data, not that a face is found. A Parametric Map in a defaced CT series’ frame is not cleaned in the face block, as an MR image there is not, and claims the option only on a verdict that its own series’ previews show no face (D-046). A Real World Value Mapping holds no pixel data, so it cannot show a face or hold burned-in text. Each item of its Referenced Image Real World Value Mapping Sequence (0040,9094) maps the stored values of the images that the item names, in Referenced Image Sequence (0008,1140), by the items of its own Real World Value Mapping Sequence (0040,9096), each to a quantity in the units of its Measurement Units Code Sequence (0040,08EA) (PS3.3 Section C.25.2), and names those images by UIDs that the run’s key replaces as it replaces their own (D-003), so a written mapping still names the written images. A mapping to a standardised uptake value, with the Radionuclide Total Dose that the Basic Profile keeps in the images that it maps, may disclose the patient’s weight, as a PET image’s own mapping may, so the QC pack lists such an instance with that indicator (D-015). Parametric Map and Real World Value Mapping use no text, UID, date, or time attribute that the IODs supported before them do not (D-022), and the places where the Basic Profile’s actions sequester them are those of the enhanced MR IODs: Responsible Person and Responsible Organization, a Parametric Map’s Referenced Performed Procedure Step Sequence without a UID to replace, its Pixel Data Provider URL, and, where its Pixel Presentation (0008,9205) isCOLOR_RANGE, an ICC Profile that is not an RGB profile (D-020, D-021). Nuclear Medicine Image, another of the IODs that radiotherapy exports carry, which the maintainer brought into the first supported release on 31 October 2026 with its own evidence, is supported too: Nuclear Medicine Image Storage (1.2.840.10008.5.1.4.1.1.20), the one Storage SOP Class that Table B.5-1 maps to the Nuclear Medicine Image IOD, which adds one IOD; the retired Nuclear Medicine Image Storage (1.2.840.10008.5.1.4.1.1.5), which Table B.5-1 does not list, is still sequestered as not a Standard Storage SOP Class. A Nuclear Medicine image holds a gamma camera’s planar views, static, dynamic, gated, or whole body, the projections of a tomographic acquisition at each angle of the detectors’ rotation, or a volume reconstructed from them, as the third value of its Image Type says (PS3.3 Section C.8.4.9). Any of them can show a face: a planar view or a projection may be lateral, as an RT Image may, and a reconstructed volume of the head may be rendered. So the QC pack lists every Nuclear Medicine image as able to show a face, whatever its Image Type and Number of Frames, for review through its series’ previews (D-015, D-017). It claims the Clean Recognizable Visual Features Option only on a verdict given on previews that show every frame of it (D-046), so where only its series’ cine strip previews it, one of more frames than the strip shows, such as most dynamic, tomographic, and reconstructed acquisitions, is held under that option asface-verdict-on-other-pixel-data, a cost in what is released rather than a disclosure; under the Clean Pixel Data Option as well, the redaction previews of each of its frames can show them all, and so can support the verdict. The run cleans no Nuclear Medicine image of the face, so one in a defaced CT series’ Frame of Reference, such as a SPECT volume reconstructed in a SPECT/CT’s frame, is held asundefaced-in-defaced-frameunless a reviewer gives it a verdict of its own (D-050). Its pixel data are cleaned and claimed under the Clean Pixel Data Option as any other image’s are (D-037). The text that only it uses and Table E.1-1 omits has rules reviewed ahead of supporting it (D-022), and it adds no place where the Basic Profile’s actions sequester an instance beyond those of every IOD, Responsible Person and Responsible Organization in the Patient Module (D-020), and an ICC Profile that is not an RGB profile, which its user-optional ICC Profile Module makes Type 1, as in the enhanced IODs (D-021). Its Overlay Plane and Multi-frame Overlay Modules are user-optional, so an overlay is removed with its whole group, as in a CT image (D-020), and its Referenced Performed Procedure Step Sequence is Type 3, in the General Series Module, so it is removed. Of the Presentation States, the six softcopy Presentation State IODs of PS3.3 Sections A.33.1 to A.33.4, A.33.6, and A.33.8 are supported, which adds six IODs: Grayscale, Color, Pseudo-Color, Blending, and XA/XRF Grayscale Softcopy Presentation State, and Variable Modality LUT Softcopy Presentation State. A Presentation State says how a viewer should show images that it names, with their grey-scale or colour transforms, shutters, masks, displayed area, rotation, and flips, and graphic and text annotations drawn over them; it holds no pixel data, so it cannot show a face or hold burned-in text, but its annotations can carry text that a person typed, such as a name, and graphics that could trace text (MIDI §1.22.3). Each names the images that it presents, in the Referenced Series Sequence (0008,1115) of its Presentation State Relationship Module, which its IOD makes Type 1, or, in a Blending Softcopy Presentation State, in its Blending Sequence (0070,0402), by UIDs that the run’s key replaces as it replaces the images’ own (D-003), so a written Presentation State still names the written images. That Referenced Series Sequence is not the Common Instance Reference Module’s sequence of the same tag, which none of these IODs includes, so it never lapses (D-022). Their attributes were reviewed ahead of supporting them (D-022), and the Basic Profile’s actions sequester them at three places beyond Responsible Person and Responsible Organization: Presentation Creation Date (0070,0082) and Time (0070,0083), which Table E.1-1 gives a plain X, are Type 1 at the top level of the mandatory Presentation State Identification Module, so every Presentation State that conforms to its IOD is sequestered underbasicandbasic-clean-descriptors, and released undertps-importandpublic-release, whose Modified Dates shifts them (D-006, D-020); the Graphic Annotation Sequence (0070,0001), which holds the text and graphic objects and which Table E.1-1 gives D, is Type 1 wherever these IODs define it, and a sequence has no dummy value, so an instance that holds one is sequestered under every preset, including under Clean Graphics, which gives it its Basic Profile action (D-021, D-041); and Overlay Data (60xx,3000), which a plain X removes, is Type 1 in the Overlay Plane Module, which all but the Blending Softcopy Presentation State include as conditional, so an instance that holds an overlay is sequestered too (D-020). How an annotated Presentation State can be released is the maintainer’s to decide; until then it is held in this way. The maintainer also decided on 7 October 2026 that the first supported release takes compressed input, which it had sequestered. An instance in one of the twelve compressed transfer syntaxes, lossy ones included, keeps its transfer syntax and encapsulated pixel data, without decoding and re-encoding, once the comment and application segments of its codestreams are cut and every frame is shown to decode to the same pixels as its source’s (Architecture item 7); one whose pinned decoding plugin is not installed, or whose frames or codestreams fail those checks, is sequestered with its reason. A JPEG 2000 or HTJ2K frame under a lossless-only syntax that was truncated so far that it drops only whole code-blocks passes (Architecture item 2) and is written as its source labels it; since every byte of its codestream is still accounted for and its metadata segments cut, that limit concerns how its pixel data are labelled, not what they could disclose. Protocol objects, such as CT Performed Procedure Protocol, derived objects that are not specific to a modality other than Segmentation, Surface Segmentation, and Parametric Map, such as height map segmentations, spatial fiducials, and the other 8 second-generation RT IODs, stay out of scope until each is supported, as above. Within the supported IODs, the rules still sequester every Enhanced PET Image instance that conforms to its IOD underbasicandbasic-clean-descriptors(D-020), and any instance whose Referenced Performed Procedure Step Sequence has no UID to replace, or whose ICC Profile, where Enhanced CT Image, Enhanced MR Image, Enhanced MR Color Image, Segmentation, Parametric Map, or the Color, Pseudo-Color, Blending, or Variable Modality LUT Softcopy Presentation State requires it, is not an RGB profile (D-021), and every report whose tree is not kept (D-047). The report says why any other instance was sequestered: it had no SOP Class UID or one that is not text, its SOP Class is not a Standard Storage SOP Class of Table B.5-1, its IOD is not supported (the report names the IOD), or its transfer syntax is missing or not supported. An instance whose Specific Character Set (0008,0005) cannot be read, such as one stored with a VR other than CS, is also sequestered, with that reason. As the maintainer decided on 12 October 2026, a data set whose Specific Character Set is not supported or is invalid, such as a misspelt Defined Term, is read in the Default Character Repertoire, as one without a value is: text in ISO 646, with no byte from 0x80 and no escape, is read as the same characters by the pydicom codec of every Defined Term of PS3.3 Section C.12.1.1.2 that the engine supports, so it is read without guessing a character set, and text outside ISO 646 is handled as below. That is a property of those codecs, not of every character set: JIS X 0201 Roman, the G0 set ofISO_IR 13, places a yen sign and an overline at 0x5C and 0x7E (PS3.5 Section 6.1.2.3), which pydicom’s codec, like the engine under a supportedISO_IR 13, reads as a backslash and a tilde. Specific Character Set is invalid where its values break the rules of PS3.3 Section C.12.1.1.2.ISO_IR 6as a single value, which is not a Defined Term, since Table C.12-2 gives the Default Character Repertoire no Defined Term, is read as that repertoire. A value of VR SH, LO, ST, PN, LT, UC, or UT that has bytes outside the Default Character Repertoire, in a data set or item to which no Specific Character Set applies, cannot be decoded reliably, since PS3.3 Table C.12-1 makes Specific Character Set “Required if an expanded or replacement character set is used” and nothing says which was used. The maintainer decided on 1 October 2026 that such text sequesters its instance only where the text would be kept or cleaned; where it is removed or replaced, the instance is de-identified, as for other content that cannot be decoded (Architecture item 2, D-027). The residual search reads such text as ISO 8859-1, in which every byte is a character (Architecture item 5). Clarification, 2 October 2026. The maintainer clarified that “the instance is de-identified” means that the transformation proceeds, not that the output may be released: a value read only as ISO 8859-1 is incomplete coverage for the residual search, and the release gate withholds the file or sends it to QC review by the value’s kind (D-027 sets out the examples). The same day the maintainer added the other IODs that RT exports carry to the target coverage, each to be supported with its own evidence; Encapsulated PDF is supported, which adds one IOD. An Encapsulated PDF holds a document, such as a treatment summary, a plan report, or a scanned form, in Encapsulated Document (0042,0011), and PS3.3 treats the patient’s identification and dates as text in it as burned-in annotation (PS3.3 Table C.24-2). Its attributes were reviewed against the IODs above (D-022), and its Encapsulated Document Series Module adds none. Its Encapsulated Document Module adds Document Title (0042,0010), which can be copied from the PDF’s own Title entry, so it is removed by Type, which empties it, and cleaned as a descriptor under Clean Descriptors; MIME Type of Encapsulated Document (0042,0012), which the IOD fixes as application/pdf, and List of MIME Types (0042,0014), which name formats and are kept; Encapsulated Document Length (0042,0015) and Document Class Code Sequence (0040,E008), which take the default; and Relative URI Reference Within Encapsulated Document (0068,7005), which is removed by Type. Its SC Equipment Module describes the equipment that captured or converted the document: Secondary Capture Device ID (0018,1010), which Table E.1-1 removes and keeps under Retain Device Identity, and its manufacturer, model, and software versions, which can be a site’s own system and are removed and kept under Retain Device Identity in the same way; and the formats it acquired, which are kept. Table E.1-1 gives the document D under every option, and no reviewed rule gives a document a dummy value, so every Encapsulated PDF that holds one is sequestered, under every policy, with that attribute and D as its reason, and nothing of it is written (Architecture item 7). Its Content Sequence (0040,A730), Type 3 at the top level, whose items are content items as in a report, is given D by the Basic Profile and has no dummy value, so it sequesters the instance too, as it does a report (D-021), except under Clean Structured Content, which cleans it. The other encapsulated documents, Encapsulated CDA, STL, OBJ, and MTL, are not supported.Rationale. Keeping the coded pixel data, rather than decoding and re-encoding them, changes no pixel value and degrades no lossy data further, while decoding every frame lets the engine check what it releases and show it in the QC previews. The Basic Profile gives Content Sequence D, and E.3.4 Note 2 warns of significant risk in de-identifying Structured Reports without the Clean Structured Content Option. Presentation States can carry graphic and text annotations (MIDI §1.22.3). De-identification of Private SOP Classes is not defined (E.1.1, Note 6 after Table E.1-1a). Supporting every Storage SOP Class of a supported IOD, including CT Image Storage - For Processing, is consistent with deciding support by IOD, and the benchmark data should include such instances. Text decoded with the wrong character set would defeat descriptor matching (D-009), the check of a source value against the dummy value (D-021), and the residual search (D-027). Text with bytes outside the Default Character Repertoire that no Specific Character Set applies to is handled as other content that cannot be decoded is, for consistency: removing or replacing it writes nothing of it into the output, whereas keeping or cleaning it would write or match text whose characters are unknown. The residual search still finds a copy of such text left in the output, because it encodes each source value again in several character sets, including ISO 8859-1, which gives the text’s own bytes back; like every form of fewer than four characters, a shorter one is listed as not searched instead (D-027), so a copy of it is not found.
Tests. Each type is sequestered and reported, and never written to the release output. The Storage SOP Classes of the first release’s 61 IODs, including the For Processing SOP Classes, both Segmentation SOP Classes, and Surface Segmentation Storage, are supported in each supported transfer syntax, the volumetric, advanced blending, and waveform Presentation States are not, protocol objects, height map segmentations, spatial fiducials, the second-generation RT IODs not yet supported, such as RT Physician Intent and the radiation records, ultrasound images, and the other Structured Reports, among them Simplified Adult Echo SR and Acquisition Context SR, and the encapsulated documents other than PDF, are not, and each other kind of SOP Class, and each other transfer syntax, is classified with its reason. Each Structured Report IOD that the release does not support, and Rendition Selection Document, which has no Storage SOP Class, uses no attribute that the reviewed IODs do not. Under every policy, the synthetic collection’s spatial registration of its MR image and deformable registration of its PET image, where released, name the collection’s one frame of reference and their images by the replacements that the written instances carry, its RT Image, where released, names the written plan, its RT Ion Beams Treatment Record, where released, names the written RT Ion Plan, which, where released, names the written structure set, RT Dose, and RT Plan, and its RT Brachy Treatment Record, where released, names the written RT Plan and RT Beams Treatment Record, its RT Treatment Summary Record the written RT Plan and RT Brachy Treatment Record, its Enhanced RT Image and Enhanced Continuous RT Image, where released, the written plan, its RT Beams Delivery Instruction, where released, the written RT Plan, RT Beams Treatment Record, and RT Image, its RT Brachy Application Setup Delivery Instruction the written RT Plan, by its study, series, and instance, its RT Radiation Set Delivery Instruction the written RT Radiation Set and C-Arm Photon-Electron Radiation, its
BINARYandLABELMAPSegmentations, where released, name the written CT series and slice, its Surface Segmentation, where released, names the written CT series and slice, and its Parametric Map and Real World Value Mapping, where released, name the written MR Image and PET Image. Under Clean Recognizable Visual Features, a Surface Segmentation, or any instance with a Surface Sequence, is held asno-face-verdictwhatever its series’ verdict. Every Parametric Map is listed as able to show a face, whatever its Number of Frames, and a Real World Value Mapping to a standardised uptake value as possibly disclosing body weight. Compressed instances of a synthetic collection, with identifying text planted in their codestreams’ metadata segments, are released with their transfer syntax and pixels kept and none of that text. An instance whose Specific Character Set cannot be read is sequestered with that reason; a data set whose Specific Character Set is not supported, or is invalid, is read in the Default Character Repertoire, its text in ISO 646 collected and its removed text outside ISO 646 read as ISO 8859-1; andISO_IR 6alone is read as the Default Character Repertoire. Text with bytes outside the Default Character Repertoire, in a data set or in an item to which no Specific Character Set applies, sequesters its instance where the text would be kept or cleaned; where it is removed or replaced, the transformation proceeds, the release gate withholds the file where the text is a person name and sends it to QC review where it is a description, and a copy of the text’s bytes of at least four characters left in the output, such as in a private element, is found by the residual search, while a shorter one is listed as not searched. Under every preset, every set of the options that the presets select that a custom policy accepts (96, Clean Recognizable Visual Features among the options), and each other option that the engine applies, taken alone, an Encapsulated PDF that shows identifying text on its page, names its author in its document information dictionary, and carries a name in its Document Title is sequestered at Encapsulated Document with D alone, and a run releases the rest of its collection and writes none of that text, nor the patient’s identity, to the release or the command’s output.
D-011: Validated overrides and derived claims#
Decision.
Validate the effective policy across L1, L2, and L3 before processing. Reject unresolved conflicts between selected options; a documented deviation never authorises a conformance claim.
A policy is a preset’s options, or a custom option set, with the resulting action of each attribute of Table E.1-1. Any option of Table E.1-1 can be composed into a policy, so that its actions can be described, and so can the Clean Pixel Data and Clean Recognizable Visual Features Options, which PS3.15 E.1.1 Note 11 leaves out of the table and which give no attribute an action: a policy lists them after the table’s options, with their CID 7050 codes, 113101 and 113102. The engine applies only a policy whose options it implements, and refuses any other before transforming anything, naming each option it does not yet apply; it applies an option once it implements the option’s actions. Validation rejects both Retain Longitudinal Temporal Information Options together, which E.3.6 makes mutually exclusive; a Table E.1-1 of another edition than the data dictionary, against which the L2 rules were reviewed; and every conflict between selected options except those
tps-importresolves.That exemption belongs to the
tps-importpreset. Where Retain Device Identity gives an attribute K and Modified Dates gives it C, and the attribute has a temporal role, the preset applies C by that role (D-007) and records Retain Device Identity as unmet, so its policy claims no conformance. The preset’s policy without one of its options, whose actions apply where that option settles nothing, such as Clean Descriptors’ fallback (D-009), resolves them in the same way; it has no preset and is never enabled itself. The same options chosen as a custom set are rejected, as is any other conflict, including one that a regenerated table adds.The engine accepts only an enabled policy, composed from the pinned tables, so a policy composed from another table is never enabled: that of an enabled preset, or that of a custom option set while
basicand each of its options are enabled (D-033).Validate every L3 removal, replacement, and retention against attribute Type, VR and VM, conditional requirements, referential integrity, and the effective profile and options. Reject a change that invalidates a supported IOD.
Check every value the engine writes, whether a replacement, a dummy value, or an L3 value, against its VR’s definition in PS3.5 Table 6.2-1 and its attribute’s VM in the pinned dictionary before writing it; a value of LT, ST, UR, UT, OB, OD, OF, OL, OV, OW, or UN is single whatever the dictionary gives, as PS3.5 Section 6.4 requires. A text value is checked as the engine sets it, before encoding adds a padding byte. Where PS3.6 gives an attribute alternative VRs, such as “US or SS” or “OB or OW”, the value is checked against the VR that applies in the data set, as the standard determines it from other attributes and the transfer syntax: for example Pixel Representation (0028,0103) decides US or SS for Pixel Padding Value (PS3.3 C.7.5.1), and Bits Allocated (0028,0100) and the transfer syntax determine which of OB and OW Pixel Data may have (PS3.5 Annex A). The checks of a value on its own accept any alternative it fits. As a text value is written, the engine also checks that the data set’s Specific Character Set can encode it, in which the Default Character Repertoire, given by an absent value or by ISO_IR 6 alone (Architecture item 5), is ISO 646 (PS3.5 Section 6.1.2.1) and a single-byte character set takes one byte for each character, and where that repertoire is Value 1 with code extensions, no character of ISO 8859-1 outside ISO 646 is accepted, since pydicom would write it in ISO 8859-1 without the escape sequence of the code extension that holds it (PS3.5 Section 6.1.2.5.3); and that the first component group of a Person Name uses only the characters PS3.5 Section 6.2.1.2 allows there. What is wrong is reported without quoting the value.
A change incompatible with a selected option requires an explicitly revised policy that is revalidated in full; an option is never dropped silently.
Derive all report wording and De-identification Method and Code Sequence content from each instance’s validated result. A run with mixed results cannot claim that every output conforms.
tps-importis the only policy that produces nonconformant output, marked as D-012 describes. Any other policy that cannot conform, such as one retaining attributes its options do not keep, is rejected, and instances of Private SOP Classes are sequestered (D-010).
Rationale. E.1.1 requires that each attribute specified to be retained “shall be retained”, and an option’s requirements override the Profile’s. Removing Patient’s Weight therefore contradicts Retain Patient Characteristics, even though removal discloses less. Maintaining IOD integrity is the de-identifier’s responsibility (E.1.1 step 2, Note 1).
Tests. The presets’ option sets; the eleven conflicts that
tps-importresolves, each modified by its role, also in its policy without Clean Descriptors, which is never enabled and still rejects any other conflict, and their rejection in a custom option set; every option of Table E.1-1 composed, and refused by the engine until it applies it; each pixel option composed with any preset’s options after them, leaving every attribute’s action unchanged, and refused by the engine until it applies it; rejection of both Retain Longitudinal Temporal Information Options together, of a table of another edition, and of a conflict that a regenerated table adds; only enabled presets, and custom option sets of enabled options, reach the engine; removal of Type 1 and Type 2 attributes; removal of retained patient characteristics; retention the profile forbids; conditional attributes; revised option sets; and agreement between report claims and inserted markers.
D-012: De-identification markers#
Decision. Markers are derived from each instance’s validated result (D-011): its policy, the method digest, and the options the instance satisfies. They are added after every other action, and change nothing else in the data set.
Every preset adds two values to De-identification Method (0012,0063), an LO attribute of VM 1-n, after the values already present: first a value that is exactly the 64 hexadecimal digits of the method digest (D-024), and then a readable value of at most 63 characters. No other digest, such as one of the runtime environment or of the run, is added. Output that already carries markers gains them only as set out below.
For conformant output, set Patient Identity Removed (0012,0062) to YES; add the CID 7050 codes for the profile and each satisfied option to De-identification Method Code Sequence (0012,0064), after the items already present and apart from any already among them; and write the readable De-identification Method value
PyMedPhys <version>; PS3.15 <edition>; <preset>, such asPyMedPhys 0.42.0; PS3.15 2026d; basic. A custom option set has no preset, so its readable value names itcustom option setinstead.The satisfied options are the policy’s options that the instance’s validated result meets. Under a policy that claims conformance, every selected option is satisfied except Clean Descriptors, which goes unsatisfied where an instance retains a descriptor string that has not passed pooled human review (D-009), and Clean Pixel Data, which an instance satisfies only where it holds no top-level pixel data or a reviewer approved its regions (D-048); such an instance carries the profile’s code but not the option’s. A descriptor that its Basic Profile action removes or replaces instead still meets the option. Clean Recognizable Visual Features goes unsatisfied likewise where an instance is held for its face review, and an instance that satisfies it also has Recognizable Visual Features (0028,0302) set to NO, whether or not its IOD defines the attribute (D-046). Markers whose satisfied options leave out any other selected option are refused, with an error that names each option left out. The profile’s code, DCM 113100, comes first, then each satisfied option’s, in Table E.1-1’s order of options. Every option of Table E.1-1 has its code, so the markers can be computed for any policy that can be composed. Each item holds the Code Value, Coding Scheme Designator, and Code Meaning of its row of the pinned CID 7050, and no Coding Scheme Version, which the Basic Code Sequence Macro (PS3.3 Table 8.8-1a) requires only where the designator does not identify the code unambiguously, as DCM does.
For
tps-importoutput, which makes no conformance claim (D-007), set Patient Identity Removed to YES; add no CID 7050 codes, keeping existing items; and write the readable valuePyMedPhys <version>; no PS3.15 claim; tps-import, which names PyMedPhys, its version, and the preset, and states that no PS3.15 conformance is claimed. Where no item was present, De-identification Method Code Sequence is left out, because the Patient Module (PS3.3 Table C.7-1) makes it Type 1C, so that where present it needs an item.For both, set Longitudinal Temporal Information Modified (0028,0303) to REMOVED, to MODIFIED where Modified Dates is applied, or to UNMODIFIED where Full Dates is applied (E.3.6), unless a stricter value is already present, and add a Contributing Equipment Sequence (0018,A001) item whose purpose of reference is DCM 109104 (De-identifying Equipment, CID 7005), after the items already present unless an equal one is among them.
Every de-identified instance names PyMedPhys in these markers, never in dummy values, apart from the Coding Scheme Designator of the dummy item of Person Identification Code Sequence (D-021). The Contributing Equipment Sequence item names PyMedPhys as its Manufacturer (0008,0070), and the readable De-identification Method value names PyMedPhys too. In the SOP Common Module (PS3.3 Table C.12-1), which each of the first supported release’s IODs includes as mandatory, the item’s only Type 1 attributes are Manufacturer and Purpose of Reference Code Sequence (0040,A170), whose item carries the code: Code Value
109104, Coding Scheme DesignatorDCM, and Code MeaningDe-identifying Equipment. Every other attribute of the item, including Software Versions (0018,1020), is Type 3. The item holds only Manufacturer, Software Versions, and Purpose of Reference Code Sequence, so it has no Contribution DateTime (0018,A002).Software Versions of the item, an LO attribute of VM 1-n, records the software that ran as four values, in this order: the PyMedPhys version, such as
0.42.0; the Python implementation, asplatform.python_implementation()gives it, a space, and the Python version, such asCPython 3.14.0;pydicom, a space, and its version, such aspydicom 3.0.2; andtomlkit, a space, and its version, such astomlkit 0.15.1. Each value is checked as an LO value, like every value the engine writes (D-011). These values are provenance of the run, not inputs to the method digest (D-024), and the release report records the same values (D-029). They are read from the running process each time the markers are computed.<version>is PyMedPhys’s full version, as in the first value of Software Versions, and<edition>is the edition of the policy’s Table E.1-1. Every marker value is checked against its VR and VM in the pinned data dictionary before it is written (D-011). A value that does not fit, such as a Software Versions value longer than the 64 characters of LO or a readable value longer than 63 characters, is never shortened or written without the version: the markers are refused with an error that names each attribute that does not fit. They are refused in the same way, before anything is written, where an attribute that they write would have an odd length in all and end in a value of its VR’s maximum length, as Software Versions could, or De-identification Method where such a value from another de-identifier follows a pair already present. With edition 2026d, every version of up to 14 characters fits every preset’s readable value;basic-clean-descriptorsgives the longest.Never set Patient Identity Removed to NO. Nonconformant output carries YES only when every deviation from the selected profile and options removes or modifies more than they require, as
tps-import’s modification of device dates does, so a policy that resolves a conflict between options by keeping the value gets no markers.On output that already carries de-identification markers, PyMedPhys’s own or another de-identifier’s, such as output de-identified a second time, the markers are added as the maintainer decided on 1 October 2026:
De-identification Method gains this run’s digest and readable value only where that pair is not already present as two consecutive values, the digest first, and otherwise gains nothing. It never gains only one of the pair, so a digest is never separated from its readable value.
De-identification Method Code Sequence gains each code only where no item already present has the same Code Value and Coding Scheme Designator, and the same Coding Scheme Version where either item has one. Items already present keep their order, and new ones follow in this run’s order.
Contributing Equipment Sequence gains this run’s item only where no item already present is equal to it: the same Manufacturer, the same Software Versions values in the same order, and the same purpose of reference code, by its Code Value and Coding Scheme Designator.
Longitudinal Temporal Information Modified becomes the stricter of the value already present and this run’s, in the order UNMODIFIED, MODIFIED, REMOVED, so that it never returns towards a less strict state. A value already present that is not one of these three, or more than one value, is refused rather than guessed at, as an earlier marker that cannot be read as its VR is, and the markers are not written. An empty value counts as absent.
Patient Identity Removed is YES, replacing any value already present.
Rationale. E.1.1, E.2, and E.3.6 require these markers in their text, not in Table E.1-1, so the table generator does not produce them. E.1.1 says codes and text are “added to” these attributes, so earlier markers are kept. The CID 7050 codes carry the profile claim, so output without them claims none, and each code comes from a satisfied option rather than a selected one because D-009 claims Clean Descriptors only after review. PS3.3 notes that De-identification Method may describe the extent of de-identification, for example a HIPAA Limited Data Set, so YES with a descriptive value is an established way to record de-identification that stops short of a profile. NO would be false for
tps-import, whose patient identity is removed, and E.1.2 has a re-identifier set NO while removing the method attributes. MIDI §1.14.3 recommends recording the de-identifying equipment in Contributing Equipment Sequence. The full SHA-256 digest fits one value exactly, since LO allows 64 characters, and the attribute is multi-valued. A shortened digest inside the readable value was rejected because a truncated digest proves less, and recording the digest in the report only was rejected because a file on its own could not be traced to its method. Software Versions takes one value for each piece of software, so each stays readable and within the 64 characters of LO, and the PyMedPhys version stands alone because the Manufacturer already names PyMedPhys. Recording the runtime there, rather than in the digest, shows what ran without changing the method’s identity (D-024). The markers’ fixed values, such as the ManufacturerPyMedPhys, the namecustom option set, the textno PS3.15 claim, and the codes, are not parameters of generated values, but the method digest covers the engine’s source files, which define them, so a change to any of them changes the digest (D-024).The digest comes first and the readable value second so that output reads cleanly with pydicom’s strict reading. An attribute whose values have an odd length in all is padded with one trailing space, which follows its last value. PS3.5 Section 6.4 allows the last value to exceed its VR’s maximum length by that space, but pydicom checks each value’s length before it removes the padding, so it reads a last value of the maximum length as too long: with a warning, or with an error under its strict reading. The readable value is last, and has at most 63 characters, so the padding never makes it too long. Putting the digest last was rejected because output whose two values have an odd length in all, which depends on the length of the version and the preset, could then not be read strictly. For the same reason, any other attribute that the markers would write ending in a value of its VR’s maximum length with an odd length in all is refused rather than written in a form that pydicom reads as invalid.
Every selected option other than Clean Descriptors, Clean Pixel Data, and Clean Recognizable Visual Features must be satisfied, because an option’s code must be present wherever the instance carries any of the option’s actions. A Retain option keeps or modifies what the Basic Profile removes, so leaving out its code would claim more removal than was done:
public-releaseoutput without the code of Modified Dates would claim that the Basic Profile removed the dates that were shifted. Longitudinal Temporal Information Modified, set from the selected options, then agrees with the codes. Clean Descriptors may go unsatisfied because the descriptors then receive the Basic Profile’s actions, which the profile’s code claims. Clean Pixel Data may, because leaving out its code claims no cleaning of the pixel data, which the profile’s code does not claim either, and an instance whose regions no reviewer has approved is held for review and never released (D-048). Clean Recognizable Visual Features may, because an instance that does not satisfy it is held for review and never released (D-046).The
tps-importreadable value keeps the conformant value’s three fields, so that the same reading finds the software, the claim, and the preset, and says in the claim’s place that none is made. It names no edition, which could be read as a claim, and is short enough to limit the version no more thanbasic-clean-descriptorsdoes.A custom option set is named by the term this document uses for it. No preset’s name contains a space, so the two cannot be confused, and the codes and the method digest identify its options. Codes follow Table E.1-1’s order of options, the order in which every policy holds them.
A value that does not fit is refused rather than shortened, because a shortened value would misstate the version or the preset. Dropping the version where it does not fit, as D-025 does for Implementation Version Name, was rejected because the readable value must name it.
The Contributing Equipment Sequence item holds only what this decision lists. Contribution DateTime would record when each instance was de-identified, a date that Table E.1-1 removes under the Basic Profile.
Software Versions is read each time the markers are computed, rather than once when the module is imported, so that it gives the versions of the software that computes them, and importing the module loads neither pydicom nor tomlkit, which PyMedPhys imports only where they are used.
An empty De-identification Method Code Sequence would make the output invalid, so it is left out rather than written.
E.1.1 has codes and text “added to” these attributes but does not address a second run, and a value, code, or item equal to one already present adds no information, so it is not added again. A run with another release or policy has a different digest, so its readable value and digest are still recorded, and a run in another runtime environment, which has the same digest unless the run is under Clean Pixel Data and its text finder’s runtime differs, still adds its Contributing Equipment Sequence item, whose Software Versions differ (D-024).
Longitudinal Temporal Information Modified must stay true of the instance. PS3.3’s SOP Common Module defines it as indicating “whether or not the date and time Attributes in the Instance have been modified during de-identification”, which describes the instance’s dates as they are now, and a later run cannot restore what an earlier one removed or shifted. Replacing the value would make
basicoutput given Modified Dates in a second run say MODIFIED for dates that were removed and may now be shifted dummy values, and Modified Dates output given Full Dates by another de-identifier say UNMODIFIED for shifted dates. The codes stay a flat set across runs, so this attribute, not the codes, carries the state of the dates.
Tests. Markers for each preset, including
tps-import, for a custom option set, including each option of Table E.1-1 alone with its code and Full Dates with UNMODIFIED, and for input that already carries markers, whose values and items are kept; the same release and policy applied twice giving exactly the markers of one run; a different digest adding its pair, and a pair that is not present as two consecutive values added; a code already present, from another de-identifier, not added again, with new codes after it; an equal Contributing Equipment Sequence item not added again, and one with other Software Versions added; the stricter Longitudinal Temporal Information Modified for every pair of present and new values; a present value that is not one of the three refused without quoting it; values within their VR and VM limits, every version of up to 14 characters fitting every readable value within 63 characters, and a longer one refused rather than shortened; the markers of every preset, with Clean Descriptors satisfied and not, and of a custom option set, written at two versions that give their De-identification Method values an odd and an even length in all, in Implicit and Explicit VR Little Endian, read back by pydicom’s strict reading without a warning, and gaining nothing when added again to what was read back; Software Versions, and De-identification Method with another de-identifier’s value of LO’s maximum length after a pair already present, refused where they would have an odd length in all and written where they would have an even one; the markers’ pair following another de-identifier’s value of LO’s maximum length, which then reads strictly; a single value of its VR’s maximum length written; markers changed after they are computed, such as to NO or to a value too long for its VR, refused before anything is written; both De-identification Method values from every preset, the first exactly the method digest and the second the readable value, and no other digest; atps-importreadable value that claims no PS3.15 conformance; codes that are rows of the pinned CID 7050, in order, for the profile and the satisfied options only, with Clean Descriptors claimed only where satisfied; refusal of satisfied options that leave out a selected option other than Clean Descriptors, Clean Pixel Data, and Clean Recognizable Visual Features, naming each option left out, except undertps-import, which needs none satisfied; a Contributing Equipment Sequence item that names PyMedPhys, has every Type 1 attribute of the SOP Common Module, and records in Software Versions the PyMedPhys version, the Python implementation and version, and the versions of pydicom and tomlkit, in that order, each a valid LO value, with a value too long for LO refused; each of the four values read from the running process when the markers are computed, so that changing its source changes it; changing the Python implementation and version and the versions of pydicom and tomlkit changing Software Versions but not the method digest in De-identification Method, so that output marked again in another runtime gains only that runtime’s Contributing Equipment Sequence item;tps-importoutput without new CID 7050 codes or an empty code sequence; no output with Patient Identity Removed set to NO; markers that quote no source value and leave every other attribute unchanged; and agreement between markers and report claims.
D-013: No Encrypted Attributes Sequence#
Decision.
The engine does not write the Encrypted Attributes Sequence and stores no recovery or consistency data in its output. Consistency comes from custodian-held keys and subject profiles outside the output (D-004). If the sequence is added later, it is for controlled sharing only and is never enabled by
public-release. The conformance statement records this interpretation.Any Encrypted Attributes Sequence (0400,0500) in the input is removed with its items, whatever its Type, before the rule for attributes that no rule covers applies (D-022). Each IOD of the first supported release defines it in the SOP Common Module as Type 1C: “Required if application level confidentiality is needed and certain recipients are allowed to decrypt all or portions of the Encrypted Attributes Data Set” (PS3.3 Table C.12-1). That condition never holds in the output, since no recipient of the output may decrypt anything in it, just as ROI Interpreter Sequence’s condition lapses once ROI Creator Sequence is removed (D-020).
Rationale. E.1.1 step 1, Note 3, deprecates other mechanisms in the data for identity recovery or longitudinal consistency “in favor of the Encrypted Attributes Data Set mechanism”. MIDI §1.17.11 calls encrypting original values into de-identified images “generally inadvisable”, especially for publicly released data. Table E.1-1 omits the sequence and both attributes of its items, Encrypted Content Transfer Syntax UID (0400,0510) and Encrypted Content (0400,0520), so, without the removal above, the rule for attributes that no rule covers would keep the sequence, keep the UID by its
definitionrole (D-003), and keep Encrypted Content as a binary value that the IOD defines there (D-022). An input’s sequence can hold original values encrypted for recipients who may re-identify them (E.1.1 and E.1.2), which this decision keeps out of the output. Giving the sequence X/Z/D, as D-022 gives the sequences it reviews, was rejected: at its Type 1C place X/Z/D resolves to D, for which D-021 gives SQ no dummy value, so every instance that carries one would be sequestered.Tests. No output contains an Encrypted Attributes Sequence or other recovery data; an instance whose input carries one is written without it, with its items removed.
D-014: No preset named after a regulation#
Decision. No preset carries a regulatory name. The documentation maps DICOM profile behaviour to regulatory frameworks without claiming compliance.
Rationale. The HIPAA Safe Harbor method is not a DICOM profile. It permits dates reduced to a year, which a DA value cannot hold, and its “comparable images” provision is open to interpretation for head imaging (MIDI §1.18.3.3).
D-015: Pixel data: detect and warn#
Decision.
Detect and report indicators of risk for review: burned-in text; reconstructable faces, including RT Structure Set contours of the head (MIDI §1.20.4); and PET series from which body weight can be recovered, such as SUV-scaled series released with attenuation-corrected images (MIDI §1.20.2). The absence of an indicator is not proof of absence.
Each instance’s attributes give its own indicators, whatever its IOD. Of burned-in text: Burned In Annotation (0028,0301) of YES; Image Type (0008,0008) whose second value is SECONDARY, since screen captures, such as dose screens, are made after the examination and usually carry text (MIDI §1.19.1); Conversion Type (0008,0064), which describes how an image was converted or captured, such as from a workstation’s screen or a scanned document (PS3.3 C.8.6.1); and an overlay group without Overlay Data (60xx,3000), whose overlay PS3.3 before 2004 let lie in unused bits of the pixel data (PS3.3 C.9.2), where it stays when the Basic Profile removes the overlay’s attributes. Of a reconstructable face: Recognizable Visual Features (0028,0302) of YES, and the contours of an RT Structure Set ROI whose RT ROI Interpreted Type (3006,00A4) or ROI Name (3006,0026) is EXTERNAL, BODY, or SKIN, the patient’s outline, or BOLUS or FIXATION, the Defined Terms of a bolus and of an immobilization device (PS3.3 C.8.8.8), which lie on the outline and can be moulded to the face, comparing the whole value whatever its case. Of a possibly disclosed body weight: Units (0054,1001) of GML or CM2ML, values scaled to a standardised uptake value (SUV), and a Real World Value Mapping Sequence (0040,9096) item, at the top level or in a functional group of an enhanced image or Parametric Map, or in a Referenced Image Real World Value Mapping Sequence (0040,9094) item of a Real World Value Mapping instance, which maps the values of the images that the item names, whose Measurement Units Code Sequence (0040,08EA) gives a Code Value or Long Code Value that contains
{SUV, as every SUV unit of PS3.16 CID 85 does; the Basic Profile removes Patient’s Weight (0010,1030) but keeps these and Radionuclide Total Dose (0018,1074), and Retain Patient Characteristics keeps the weight itself, so that under that option these indicators say no more than the written instance does (D-038). These indicators mean possible disclosure, not demonstrated recovery: recovering the weight depends on the SUV normalisation, of which SUVibw uses height and sex rather than weight, on the activity calibration, and on compatible dose timing, possibly using an activity concentration mapping of the same values (PS3.3 C.7.6.16.2.11) or SUV-scaled images released with attenuation-corrected images of the same acquisition. An attribute that cannot be read as its VR in the pinned data dictionary is reported as unreadable evidence of the risk it bears on. A received NO counts for nothing, as an absent attribute does. Each CT, MR, PET, or RT Dose series that is a volume, whose instances of that modality, single-frame or enhanced, hold at least two frames that are not localizers, an RT Dose counting only where it holds at least two frames itself, is reported as one from which a face may be reconstructed, whatever its slice spacing: how finely it samples the face changes how readily the face is recognised (MIDI §1.18.3.2), but no spacing makes it safe, and only the pixel data could show whether it covers the face. An RT Dose grid shows the patient’s outline wherever the planning system computed dose only within it, and its build-up at the skin shows it otherwise; this is an inference, not a published result. The CT, MR, and PET localizers of a series, whose Image Type has a third value of LOCALIZER, are reported apart, since a lateral localizer can show the face in profile, although no study has measured recognition from one. Each RT Image, of RT Image Storage, Enhanced RT Image Storage, or Enhanced Continuous RT Image Storage, is reported apart too, whatever its Image Type, gantry angle, or Number of Frames: each holds projections (PS3.3 C.8.8.2, A.86.1.15.1, and A.86.1.16.1), and a lateral one, such as a DRR or a simulator, portal, or kV image, can show the face in profile as a localizer can. It is recognised by its SOP Class whatever its Image Type, since the standard Defined Terms of the third value for an RT Image (PS3.3 C.8.8.2) do not include LOCALIZER, though an implementer may extend them (PS3.5 6.3). Each Nuclear Medicine image (Nuclear Medicine Image Storage) is reported apart too, whatever its Image Type or Number of Frames: by its Image Type’s third value it is a planar view, which may be lateral, the projections of a tomographic acquisition, among them lateral views, or a volume reconstructed from them. Its frames are placed by the items of its Detector Information Sequence (0054,0022), not as a CT, MR, or PET slice is, so it is not counted as a frame of a volume, and an Image Type that cannot be read cannot hide it. Its resolution, coarser than CT’s, changes how readily a face is recognised, not whether it may be. A volume, localizer, RT Image, Enhanced RT Image, Enhanced Continuous RT Image, or Nuclear Medicine image whose Body Part Examined (0018,0015) or Anatomic Region Sequence (0008,2218), at the top level or in the Frame Anatomy functional group of an enhanced image, names a region of the head or neck, or one containing it, in a reviewed list from PS3.16 Annex L, is also reported as showing the head or neck. Each Segmentation, of Segmentation Storage or Label Map Segmentation Storage, is reported as one from which a face may be reconstructed, whatever its segments are labelled, since a segment of the skin or body traces the patient’s outline as a structure set’s outline does, and a BINARY segment is a 1-bit mask of it; it is reported as showing the head or neck where its Body Part Examined, its Anatomic Region Sequence at the top level or in the Frame Anatomy functional group, or a segment’s Anatomic Region Sequence or Segmented Property Type Code Sequence (0062,000F) names such a region, as a parotid gland’s property type does. A Surface Segmentation, whose segments are meshes, and a Height Map Segmentation are not assessed. Each Parametric Map is reported as one from which a face may be reconstructed, whatever its quantity and Number of Frames, since a map of the head shows its outline wherever the quantity differs from the air around it (an inference, not a published result), and one frame of it can be a sagittal plane; it is no frame of a volume, and it is reported as showing the head or neck where its Body Part Examined, or its Anatomic Region Sequence at the top level or in the Frame Anatomy functional group, names such a region.Claim the Clean Pixel Data Option only for an instance without top-level pixel data, or whose regions a reviewer accepted or added to (D-048). Claim the Clean Recognizable Visual Features Option only for an instance that cannot show a face, or in which a reviewer found no recognisable face (D-046).
Keep Burned In Annotation (0028,0301) and Recognizable Visual Features (0028,0302) as received, except that an instance that satisfies the Clean Pixel Data Option has Burned In Annotation set to NO (D-048), and one that satisfies the Clean Recognizable Visual Features Option has Recognizable Visual Features set to NO (D-046); the engine removes a face from pixel data only under the Clean Recognizable Visual Features Option (D-050). Never change either to NO otherwise, and do not treat a received NO as evidence of safety.
Report the indicators of each released or held instance, its own and its series’, in the confidential QC pack by instance (D-016), and in the release report as counts of the instances with each risk and each indicator, by disposition, naming none.
A reported risk does not waive the
public-releasegates (D-017). Optical character recognition and defacing may later be added as optional plugins.
Rationale. PS3.15 sets these attributes to NO only as part of the Clean Pixel Data and Clean Recognizable Visual Features Options (E.3.1 and E.3.2). The engine claims each only by review, apart from instances that hold nothing to clean (D-048, D-046). Neither attribute is in Table E.1-1, so L2 needs an explicit rule. RT Dose grids, localizers, and bolus and fixation ROIs became indicators when the maintainer chose on 12 October 2026 to implement the Clean Recognizable Visual Features Option by attestation and then CT defacing, since every object that can carry the face must be found before any of them can be cleaned or attested. RT Images became one when the maintainer chose on 25 October 2026 to bring RT Image into scope, for the same reason. Segmentations became one when the maintainer chose on 25 October 2026 to widen the scope to them, for the same reason, and Nuclear Medicine images and Parametric Maps when the maintainer chose on 31 October 2026 to bring them into scope; a Real World Value Mapping’s mapping to an SUV became an indicator of body weight then too, since it discloses as much as a PET image’s own mapping does.
Tests. The L2 rules keep both attributes; received values pass through unchanged, no output changes either attribute to NO except Burned In Annotation under D-048 and Recognizable Visual Features under D-046, and detection results appear in the report.
D-016: Confidential QC separate from release reports#
Decision.
Logs, standard output and standard error, warnings, exception messages, output file and directory names, and release reports contain no source attribute values, original paths, or keys. They use attribute paths, opaque object identifiers, rule identifiers, and aggregate results.
Each instance is written to
<Patient ID>/<Study Instance UID>/<Series Instance UID>/<SOP Instance UID>.dcmbelow the output directory, from its replacement Patient ID (D-005) and replacement UIDs (D-003). Names therefore hold only ASCII digits, upper-case letters,.and-, and the.dcmsuffix, and a path below the output directory has at most 160 characters. Where the policy keeps a Study, Series, or SOP Instance UID, as the Retain UIDs Option does, the file is named by that UID’s keyed replacement, the name that the Basic Profile gives the same instance under the same key (D-040); any other value that is not a replacement names nothing. Instances that share a file name, and so a SOP Instance UID, are never renamed: D-026 sets what happens to them, and their run positions appear only in the confidential QC pack. The output is a plain directory tree, not a PS3.10 File-set: a File ID component holds at most eight characters from A to Z, 0 to 9, and underscore (PS3.10 8.2 and 8.5), which a UID cannot meet, so no DICOMDIR describes it.A QC pack contains only the retained strings, contextual excerpts, and image previews needed for review. It is written to an explicitly designated location restricted to authorised reviewers, treated as potentially identifying, excluded from release directories and archives and kept out of the source directory, and has documented retention and deletion.
A run’s QC pack is the JSON document
qc-pack.json, labelled with its format,pymedphys-deid-qc-pack/34. It lists each input by its run position and source path, with the SHA-256 of the source file as the run’s first pass read it, with the SHA-256 of the pixel data of the file written of each released or held input, as the gate read it, which binds a face verdict to the pixel data that the reviewer saw, recorded only where previews that could show a face, which are not its contour sheets or its sheets of a series’ eyes, draw every frame of them from the first, as a volume’s projection and surface render draw each of its slices, taking a slice into the pixel or voxel nearest it by its maximum where slices are closer than those, and for an RT Dose only where its dose-levels previews do, since its cine strip is windowed to the highest doses and an Otsu render of a series of its planes shows one level, and for a Segmentation only where its segments sheet does, since its other previews show a segment as windowed values, not the surface that it traces (D-017), nor for an instance listed as not previewed, whose native Pixel Data hold more bytes than its frames and one byte of padding, or with a frame that holds more than one of the stored values that Pixel Padding Value and Pixel Padding Range Limit name, which previews draw as one black or as no patient (D-017, D-046), and with the SHA-256 of the contours of each released or held RT Structure Set as written, which binds the verdict on its series to the contours that the reviewed run wrote, recorded only where the pack’s contour sheet shows them (D-017, D-046, D-052), and with the SHA-256 of the deformation grids of each released or held instance as written, which binds the verdict on its series to the grids that the reviewed run wrote, recorded only where a grid sheet of each kind shows each of them, or where it holds none (D-017, D-046), and with what the run did with it: its output path if released or a duplicate of one released; the opaque per-run label by which the release report refers to it, S-0001 onwards at one width, and why, if sequestered, as the maintainer decided on 2 October 2026 (D-026); and why, if held for review or refused; each residual by instance and place, with an excerpt of up to 48 bytes before its offset and 96 from it, decoded with the residual’s encoding, or ISO 8859-1 where Python cannot decode with it, and with each undecodable byte and each backslash written as a backslash escape; each value left out of the search, because the policy retains it, it equals a constant that the engine always writes, it cannot be decoded inside a removed sequence, or it is a UID that the pinned tables register, and each form not searched, by instance and place, as the maintainer decided on 2 October 2026 (D-027); each distinct retained string with every place it was retained, a retained string being a value that the instance’s plan keeps as it is, in an element with a text VR other than UI, outside any removed sequence, and other than Specific Character Set, an instance whose retained string cannot be decoded for review, such as text outside ISO 646 where no Specific Character Set applies, being sequestered rather than released unreviewed (D-017); and what descriptor cleaning wrote for each ROI Name, renamed, empty, kept, mapped, emptied, held for review, or emptied unreviewed, with why a held name was held and the names of the run’s institutional list that it matched (D-009); what descriptor cleaning decided for each value of each free-text descriptor that it read, kept, kept by vocabulary, mapped, emptied, or held, with why a held value was held and what each would write, and whether the element was written with those values or took the action without Clean Descriptors, each by its tag or, for private text, by its private creator, group, element within the block, and VR (D-009, D-035, D-036); each first-pass finding that the run reports without acting on it, at each instance it names, with its kind, the attribute’s tags, and its count (D-026); each study whose instances name several patients that the run sequestered where it was told to, by the run positions of its instances grouped by patient as the first pass grouped them, so that a curator can find the instances of another patient and correct them (D-026); each instance that the run released or held in a defaced CT series’ Frame of Reference, naming none, or referring to a defaced slice, that it does not clean of the face, with whether its previews show its pixel data, contours, and deformation grids whole, for a face verdict of its own (D-050); each instance in a high-risk category, with the indicators of risk in its pixel data that put it there (D-015, D-017); each series of released or held instances that is a CT, MR, or PET volume, or that holds a Segmentation, with the instances that make it one, and the attributes that name the head or neck and the instances that hold them, and each attribute that its series assessment could not read, the series being grouped by the source’s Series Instance UID, which the pack does not write (D-015); each series of released or held instances, by the run positions of its instances, grouped the same way, by which a reviewer gives the series a face verdict (D-017); each CT series that the run defaced and held because its eye ROIs disagree with the globes that its face block was found from, by the run positions of its held slices, with the SHA-256 that binds a reviewer’s confirmation of the block to the series’ source files and the block, and at most oneseries-eyessheet of its globes beside its eye ROIs, drawn from its slices as received (D-050); each released or held RT Dose with more dose in a defaced series’ face block than the run sets to zero there, by its run position, with the SHA-256 that binds a reviewer’s choice for it to its source file and the block, the choice that the run applied, if any, and the greatest stored value in the region as a fraction of the grid’s greatest, to four decimal places, for the reviewer to weigh what setting it to zero would take (D-051); each released or held instance whose Pixel Data the Clean Pixel Data Option cleaned, with why it is held, its SOP Class UID, which decides the frames that its review requires (D-059), its number of frames, the Rows and Columns of each, and the regions blacked out in each frame, by frame index from 0, each region as[top, left, bottom, right]in pixels from the frame’s top left corner, with the bottom row and right column excluded, which of those regions reviewed region rules gave, each of which is among the regions of every frame, and, for compressed Pixel Data, the SHA-256 of its frames as decoded (D-037, D-048); and each image preview for D-017’s and D-037’s review, by its file in apreviewsdirectory beside the pack, with the frames it shows, by run position and frame index, how many frames its series or instance has, a grid sheet giving instead the index of its grid and how many grids its instance holds, and the file’s SHA-256, and each instance whose pixel data could not be previewed, whose contours could not be shown, for an RT Dose, whose dose levels could not be drawn, for a Segmentation, whose segments could not be drawn, or, for an instance that holds a deformation grid, whose grids could not all be drawn, with why; a cleaned instance has one preview of each frame, in order, each followed by the frame’s review frame, which the redaction review app shows (D-059), unless it is listed as not previewed. It also records, under a new random salt for each run, the salted digest of the reviewed ROI names and descriptors lists that the run’s descriptor cleaning applied and of the reviewed region rules that its Clean Pixel Data applied, with the salt, or null for a run that states none, which a risk assessment of the run binds (D-053). Its opaque reference is random,A-and 32 hexadecimal digits, not derived from its content. Under Clean Pixel Data the pack is more sensitive than the release, and than packs before format 5, since each frame with regions is previewed as received, with the burned-in text that the release lacks. It is also larger: each cleaned frame is a PNG at full resolution, before compression two bytes a pixel, plus the gutter, for a monochrome frame without regions, and nine bytes a pixel, plus the gutters, for one with them, and its review frame two bytes a pixel more, or three for colour, so a 300-slice CT of 512 by 512 pixels with regions in every slice adds about 870 MB before compression, and the run holds the PNGs, not decoded frames, until it writes the pack. A run that reads an attested pack back takes only the current format, so a pack written in an earlier format, before a change such as this one, is written and attested again. Each run writes its QC pack before it publishes the release, from each input’s outcome and what its transform and gate found, so a release never exists without one; a pack that cannot be written publishes nothing, and the pack of a release that cannot then be published is removed, or named in the error if it cannot be. The location has no default, and a run checks it before it creates anything. It must be neither inside the source, release, or staging directory nor contain any of them, compared by resolved path, without case on Windows and macOS, and by the device and inode of each existing directory, which finds a directory spelt otherwise on a case-insensitive share or reached through a bind mount; the checks are repeated once the location is created. It must be new or an empty directory; on POSIX an existing one must belong to the current user and grant its group and others no access, and the pack’s directory is opened without following a symbolic link and given mode 0700, as is itspreviewsdirectory, which holds a copy of the marker, and its files 0600, while on Windows access rests on the location’s access control lists. A marker file,.pymedphys-deid-qc-pack, written first, lets a release step refuse any tree that holds QC material, or a symbolic link to some, and a tree that cannot be read is reported rather than passed. A handling notice beside the pack states that it may identify people, is for authorised reviewers only, is never copied into a release, and is deleted once the review, the attestation, and the custodian’s documented retention period no longer need it. No file is overwritten, and errors name the check that failed and the operating system’s reason, never a path or value.Key and subject-profile stores are separate custodian-controlled state and are included in neither. The reviewed-names list that ROI name cleaning reuses (D-009) is confidential state too, since it holds source ROI names verbatim and persists across runs. The maintainer decided on 1 October 2026 that it is held in the custodian’s store with the key and subject profiles, protected as they are (D-004), and included in neither; only its keyed digest enters the method digest (D-024). The reviewed descriptors list (D-009) and the reviewed region rules of Clean Pixel Data (D-037), which hold manufacturers’ and model names, are kept in the same way.
Release reports record an opaque attestation reference and outcome, not the review material.
A reviewer attests to a QC pack once, in
attestation.jsonbeside it, labelledpymedphys-deid-qc-attestation/7, naming themselves and the time in UTC, stating whether they reviewed every distinct retained string, every series, and every instance in high-risk categories (D-017), and giving the outcome, attested or rejected; attested needs all three reviews. It may also give a face verdict for any of the pack’s series, named by the run position of its first instance: absent where the reviewer saw no recognisable face in its previews, and present where they saw one. It may confirm the face block of any series that the pack lists among its eye checks, named by the run position of its first held slice there, where the pack has the series’ sheet of its eyes and the reviewer saw in it that the globes found are the patient’s eyes, whatever the eye ROIs show; the attestation records the confirmations, in order and each once, inconfirmed_blocks, an outcome of rejected confirms none, and a later run’s face review gives each confirmed block’s SHA-256 (D-050). It may give a dose choice for any RT Dose that the pack lists among its dose checks, named by its run position: as written, which has a later run write it as received, so that a verdict of absent on its series, from its own dose-levels previews, which drew it as received, releases it; or set to zero, which has a later run set it to zero in the block anyway, beyond the fraction, which only a verdict on that later run’s previews of it so releases. The attestation records the choices, in order and each once, indose_choices, an outcome of rejected gives none, and a later run’s face review gives each by the SHA-256 that binds it, or, for an RT Dose that the attestation gives none, the choice that the pack records its run applied (D-051). It may give a face verdict of its own on any instance that the pack lists among its undefaced instances as shown, named by its run position, from that instance’s own previews, which a verdict on its series does not cover; the attestation records them, in order and each once, ininstance_faces, an outcome of rejected gives none, and a later run’s face review takes each instance’s file by its own verdict (D-050). The previews show each instance as the run wrote it, and a verdict covers only the pixel data that the run wrote, by their SHA-256 in the pack, so a CT series judged as received is not released defaced by a later run under the option (D-050), and a run under the option previews it defaced. A verdict is the reviewer’s judgement, the outcome does not depend on it, and the release report does not record it; a later run of the same files under the Clean Recognizable Visual Features Option follows it (D-046). It may likewise give a redaction verdict for any instance whose Pixel Data the pack lists as cleaned and previewed, named by its run position: accepted, where the pack’s regions cover every burned-in text that the reviewer saw in its previews; revised, with the finder’s regions, by frame, that the reviewer drops, and the regions that they draw, so that the regions kept and drawn cover every burned-in text that the reviewer saw, each in the form that the pack gives its own, in a frame that the instance holds, and within the Rows and Columns that the pack records for it; or rejected. An accepted or revised verdict also records the frames that the reviewer was shown, which must include every frame that its review requires, and the mode of its review, every frame or only the frames with a region, which attesting finds from the instance’s SOP Class and records (D-059). A later run of the same files under the Clean Pixel Data Option follows them, and the release report does not record them (D-048). An outcome of rejected takes no verdict of either kind, since a rejected attestation’s verdicts would release nothing: attesting refuses one, and a later run refuses a rejected attestation as it does a pack that is not attested (D-046, D-048). The attestation records the SHA-256 of the pack’s file, which records the SHA-256 of each of its previews, so a pack or preview changed after it was attested is refused, and a pack whose previews do not match it cannot be attested. The attestation is confidential with the pack, since it names the reviewer, and the release report records only the pack’s reference, the outcome (attested, rejected, or not attested where no attestation has been written), and the releaser’s two confirmations described below, each true, false, or not stated. As the maintainer decided on 6 October 2026, a public command records the attestation in the QC pack’s directory, through the same library function, naming the pack’s directory, the reviewer, the outcome, each review done, and any face verdicts, confirmed blocks (--block-confirmed), dose choices (--dose-as-written,--dose-set-to-zero), and instances’ own face verdicts (--instance-face-absent,--instance-face-present), and reads the redaction verdicts from the file that the redaction review app saved beside the pack (--redaction-verdicts, D-059), with each region that a revised verdict drops or draws in its summary, beside the file in the pack that previews its frame, for the reviewer to check, and kept out of thepymedphyscommand line until the first supported release, like the tool’s other commands. It refuses a directory that holds no QC pack, and neither its summary nor its messages quote the reviewer or a path. It does not change the release report published with the run, which records the outcome when the run wrote it, not attested, since the design does not provide for rewriting a published report; the attestation stays with the pack, from which the record a report takes is read. The person releasing the data may also confirm in the attestation, each yes or no and neither required, that the output was checked for its intended use and that its residual risk was accepted under the institution’s governance; the confirmations hold no text, are bound to the pack with the rest of the attestation, and reach the record that a release report takes as their outcomes alone, since fitness for a use and an acceptable residual risk depend on the purpose and the recipient, which only the releaser knows. This was decided on 6 October 2026 for the first release, which assigns both confirmations to whoever releases the data and has each run’s release report also summarise the engine’s structural checks of its output.
Rationale. Human review needs material that may still identify people; routine diagnostics and distributable reports do not. Names built from replacement values are the same under one key in every run and processing order, whereas renaming instances that share a name would make each name depend on the other instances, and so rename earlier output when an incremental export adds instances. Naming a file by its replacement SOP Instance UID lets a reviewer find output from the identifiers in reports. The 160-character bound leaves 98 characters for the output directory within the 259 that Windows allows a path without long-path support.
Tests. Captured logs and errors contain no source values or paths; residual search results and errors contain no source value in any form; output names contain no source path, file name, or value, are portable and within the length bound, and are refused for any value that is not a replacement; instances that share a file name are found by their run positions, not renamed; release archives contain no QC or state artefacts; the QC destination and access requirements are enforced; and a reviewer can locate affected output from opaque identifiers.
D-017: Public-release risk assessment#
Decision. A
public-releaserun is marked ready for release only when three gates pass: statistical disclosure control, pixel and face review, and a human QC attestation.Statistical gate. Accept a maximum per-subject re-identification probability of 0.09 by default, or 0.05 when selected, under an explicitly selected and validated model.
The assessment names and versions the model and its implementation. It defines the attacker’s assumed knowledge, including knowledge of membership, and identifies the reference population and sampling assumptions, or justifies assessment within the release cohort. It records matching variables, generalisation, missing-data handling, uncertainty, and exclusions.
It counts distinct subjects, not images, frames, or visits, and accounts for linked longitudinal records and earlier linked releases. A sample-based
1/kcalculation is permissible only with a documented known-membership or equivalence-class model.The assessment is bound to the exact collection and policy versions, and any change requires reassessment. A missing model, incomplete subject coverage, an unavailable estimate, or a failed threshold fails the gate; no default score substitutes.
A documented external assessment may supply the evidence, recorded and bound as D-053 sets. An automated estimator is enabled only after it has been selected and validated.
The assessment states whether keeping machine identity, such as Station Name and Device Serial Number, would raise the risk above the threshold (D-053). As the maintainer decided on 24 October 2026,
public-releaseomits device identity whatever that statement says, so the preset does not meet MIDI-BP-04’s recommendation to keep machine identity unless it is shown to raise the risk above the threshold. Keeping it because an assessment allowed it would change the policy that the assessment is bound to, so the assessment would not cover the output released; and adding Retain Device Identity to the preset would conflict with Modified Dates on the eleven device and beam hold dates and times that onlytps-importresolves, at the cost of any conformance claim (D-011). Machine identity in a public release therefore needs a policy of its own, released only where an assessment of that policy’s output, with machine identity among its matching variables, passes the threshold.The assessment also states how the residual risk of the institutional identity that the policy keeps was assessed, and whether the assessment supports keeping it (D-053), since MIDI-BP-05 allows a release to keep the identity of an institution or other organisation only where a residual risk assessment supports keeping it.
public-releaseomits Retain Institution Identity, but keeps values that can name an institution under every policy, such as the codes of local coding schemes, a local scheme’s Coding Scheme URL, and the Manufacturer of a device made in-house (D-022). No record can be made without the statement, so nopublic-releaserun is ready for release without one. The engine records the statement without interpreting it, as it records every statement of the assessment, so whoever reviews the record reads whether the assessment supports keeping those values, and the human review gate’s reviewer sees each of them among the retained strings. The maintainer decided on 26 October 2026 that the statement is free text that the engine records without acting on its answer, rather than an answer that the statistical gate checks, and that this statement, with that review and the releaser’s acceptance of the residual risk, meets MIDI-BP-05 forpublic-release.
Human review. Review every distinct retained string, every series (by maximum intensity projection or cine strip), and every instance in high-risk categories. Potentially reconstructable facial information blocks release unless a risk assessment reference is recorded. Since
public-releaseselects the Clean Recognizable Visual Features Option, its run itself holds every instance that can show a face unless the reviewer found none (D-046), so under the preset such a reference cannot release a face. For each series, the reviewer may record whether its previews, such as the renders of its skin surface, show a recognisable face; the pack records the SHA-256 of each source file, so the verdict is bound, through the attestation’s digest of the pack, to the files the reviewer saw (D-016). Review material follows D-016.The QC pack previews the files that the run released or held for review, so that a reviewer sees the pixel data as written, with any region that the Clean Pixel Data Option blacked out (D-037). A series, the instances that share a Series Instance UID, ordered along the normal where they share an orientation and every one has a position, or else by Instance Number where every one has one, or else by run position, is shown as a cine strip of up to 16 frames, evenly spaced from its first frame to its last, each scaled to fit 256 pixels. Each volume that a series forms, at least three slices of one size, orientation, and pixel spacing, at distinct positions along the normal, is also shown as a frontal maximum intensity projection, projected along the anterior-posterior axis, head up and with the patient’s right on the viewer’s left. A volume stacked along the normal with axes along the patient’s three directions, each with its other two direction cosines at most \(10^{-4}\), is sampled to square pixels, each slice also taken into the pixel nearest it by the maximum, so that every slice is drawn where slices are closer than the pixels. Any other, with a gantry tilt, whose rows or columns are turned about the left-right axis or whose slices are offset within their plane, or oblique, such as an oblique MR series, is sampled by nearest neighbour to cubic voxels along the patient’s axes, each voxel taking the nearest slice along the slices’ normal and the nearest pixel within it, and also the pixel of every slice whose plane crosses it, by their maximum, so that every slice is drawn, and only then projected, so that the projection superimposes nothing that a frontal view keeps apart; its row and column directions must each be of unit length, and perpendicular, within \(10^{-4}\), and a volume that is not is not a volume. Its voxels are of its smaller pixel spacing, or larger where needed to keep each axis within 1,024 voxels and the lattice within \(2^{24}\) voxels, about 0.9 mm for a head, so that it takes seconds. A slice is a single-frame instance, placed by its Image Position (Patient), Image Orientation (Patient), and Pixel Spacing, or a frame of a multi-frame instance, such as an Enhanced CT, Legacy Converted Enhanced CT, Enhanced PET, or Enhanced MR image, placed by its Plane Position (Patient), Plane Orientation (Patient), and Pixel Measures functional groups, each in the frame’s item of the Per-frame Functional Groups Sequence or in the Shared Functional Groups Sequence, never both (PS3.3 C.7.6.16.1.1), where every frame of the instance has them. The frames of each stack and time point, by the Stack ID and Temporal Position Index of their Frame Content functional group, form a volume of their own, since the union of frames at one position at two time points, as of a dynamic or multi-phase acquisition, could hide the surface of either, as D-052’s segments sheet refuses for a Segmentation; frames at one position in one stack and time point form no volume unless they part into phases. Slices of a group, single-frame instances or frames of one stack and time point, that repeat a position along the normal, within a micrometre, as the time points of a respiratory-correlated CT or a perfusion scan, the phases of a contrast study, or two acquisitions that overlap do, are parted into phases by the time point or acquisition that each names, never by its order, each phase forming a volume of its own: a single-frame instance by its Temporal Position Identifier (0020,0100), or by its Acquisition Number (0020,0012) where any single-frame instance of the group names no Temporal Position Identifier, and a frame by its Frame Content group’s Stack ID and Temporal Position Index, or by its Frame Acquisition Number (0020,9156) where any frame of the group names neither, each compared as an integer where it reads as one; a single-frame instance and a frame are never in one phase, and slices that repeat a position and that nothing parts, or a phase that still repeats a position, form no volume. A series whose slices do not repeat a position is one group, whatever its slices name, as before. The surface renders of a series are sampled in batches, in order, of at most \(2^{26}\) voxels in all, 256 MiB as float32, a volume that samples more being sampled alone, and each batch after the first reads its files again, each volume’s projection being accumulated with its batch and each preview encoded as a PNG as soon as it is drawn, so that the surface samples and projection slices that a series of many volumes, such as the forty time points of a perfusion scan, holds at once are those of its largest batch, and only the PNGs of its previews, not their images, are kept; the previews are the same, and in the same order, in any batches. For the same reason, those labels group frames only within their instance, or within its Concatenation, whose SOP Instances hold one Multi-frame Image between them, since PS3.3 C.7.6.16.2.2.4 lets another SOP Instance reuse a Stack ID, which is unique only within a Dimension Organization UID or else a Concatenation UID: frames of two instances that no Concatenation joins, and an instance’s frames and the single-frame instances of its series, never share a volume, though their labels match and their positions interleave, and the frames of an instance of more than one Dimension Organization UID form none. A frame is rescaled by its own Pixel Value Transformation functional group where the instance has one, and then its frames form a volume only where every frame’s Rescale Slope and Rescale Intercept can be read, so that no volume joins frames whose values cannot be compared. An instance any frame of which its Rescale Slope and Rescale Intercept, though finite, take beyond float32, or collapse into fewer than 256 steps of float32 where its stored values differ, as a slope too small for float32 rounds to 0, is listed as not previewed, since every preview drawn of it would be blank or of one value though it listed every frame. So a multi-frame instance of more frames than its cine strip shows is drawn whole, and the pack, from format 28, records the SHA-256 of its pixel data, so a face verdict on its previews can release it, as one of single-frame instances; and from format 29 a volume whose axes do not lie along the patient’s is drawn whole likewise, so a verdict can release every slice of a gantry-tilted head CT or an oblique MR series, which its cine strip alone showed before. A series with a colour instance or a Segmentation forms no volume, a Segmentation being shown by its segments sheet. Each such volume is also shown as six renders of its skin surface, head up, from the front, at 45 degrees to either side, in both profiles, and from behind: the surface of the voxels at or above -300 HU for CT whose values are Hounsfield units, its Rescale Type HU, or absent for a CT Image instance, which PS3.3 C.8.2.1 allows only for Hounsfield units, or Otsu’s threshold for any other, such as MR, PET, or CT of other units, since a fixed level in other units could enclose the air around the head and hide its face, with pixel padding counted below every other value, sampled by nearest neighbour to cubic voxels of 2 mm, or of its smallest spacing where that is larger, however long the volume, so that a long volume’s renders are taller rather than coarser, each slice also taken into the voxels nearest it along the slice axis by their maximum, so that every slice is drawn where slices are closer than the voxels, or, for a volume whose axes do not lie along the patient’s, by the same nearest-neighbour rule along its slices’ normal and within each slice, each slice also taken into each voxel that its plane crosses, as for its projection, seen at the first such voxel along each ray, and shaded by Lambert’s law with the light at the viewer. A volume more than 2,000 mm long, or more than 1,000 mm from left to right or from front to back, as for a contour sheet’s frame, is neither rendered nor projected, so that its slices beyond its cine strip are held. Pixel padding is shown black, and lies below every surface’s threshold. An RT Dose is shown by its dose levels: each RT Dose instance of two or more frames whose Grid Frame Offset Vector is evenly spaced, sampled as its axes allow, each frame at its offset along the normal, and each such volume of RT Dose planes, as rows of those six renders, one of its support, the voxels of any dose above 0 after Dose Grid Scaling, and one at each fraction of its greatest dose of 0.5, 0.2, 0.1, 0.05, and so on down, whose dose is above its smallest dose above 0, each plane of a volume scaled by its own Dose Grid Scaling; and each RT Dose plane of one frame in no volume as a map at full resolution, grey by how many of those levels each pixel reaches, so that each level’s outline is an edge. Each level’s row of a grid or volume is followed, where a ray of the frontal view, the view from behind, or a profile crosses its surface more than twice, by a row of its cavities and a row for each further crossing, as a contour sheet draws an ROI that hides its own surface, so that a lower dose enclosed by a higher one is shown; each level’s rows are separated from the next level’s by grey rows and from each other by black, so that each level’s group can be told apart. A sheet that would be taller than 32,768 pixels is not drawn, so its grid is held, and a level’s rows of further crossings are counted before any is drawn, so that rows that would not fit are neither drawn nor found. Nor is a sheet or map of more than 40 levels drawn, which any one grid of 32-bit stored values stays within, since it needs at most 29; only a series of planes whose scalings differ by many decades needs more, and planes whose scalings span float32’s range could otherwise take minutes to render. An RT Dose that no dose-levels preview shows whole, for any of these reasons or any other below, such as a scaling that float32 loses or a grid that cannot be placed, is listed as not previewed, as
dose-levels-not-shown, though its other previews are kept, such as its cine strip and, where it was cleaned, a redaction preview of each frame, so that the reviewer sees why it is held and can still give its redaction a verdict. Only an RT Dose by its SOP Class UID whose stored values are not padded, not rescaled, and scaled by a finite Dose Grid Scaling above 0 to doses that float32 holds, none other than 0 taken to 0 or to a magnitude below a normal float32 and none to infinity, is shown so, since a padded one has stored values that are read as no dose, and a scaling that float32 loses would leave a dose out of every level; a grid of no dose shows an empty support. A grid whose stored values are signed, by Pixel Representation, as an RT Dose of Dose TypeERRORstores the difference between two doses, can hold doses below 0, and a face can be outlined by them as by doses above 0, so its sheet is two ladders, each as above: that of its doses above 0, then, after white rows, that of the magnitudes of its doses below 0, from their support, the voxels of any dose below 0, down to each fraction of the greatest magnitude below 0 that is above the smallest, each voxel taking the least of its slices into the second ladder as it takes the greatest into the first, so that every slice is drawn in both; a series of RT Dose planes any one of which is signed is shown so too, and a signed plane in no volume is mapped as two maps side by side, of its doses above 0 and of the magnitudes of those below, between white columns. Every edge of the region at or above a dose of either sign is then an edge in one ladder or the other, including one where the dose changes sign, as at the skin where anERRORgrid’s difference changes sign, which a single ladder of magnitudes would not show, since the magnitude can be the same on both sides. A signed grid with no dose below 0 still has the second ladder, its empty support, so that every signed grid’s sheet is laid out alike. Each ladder is bound by 40 levels, as an unsigned grid is, and the sheet as a whole by its height, so a signed grid is shown only where both ladders fit. A planning system either sets dose to zero outside the body, so that the support outlines the skin wherever the grid reaches past it, or computes a dose in air, so that dose falls steeply across the skin. The region at or above a level lies inside the region at or above any lower one, and neighbouring levels, and the lowest level and the smallest dose, are at most a factor of 2.5 apart, so an outline that holds over a band of dose wider than that shows in at least one row; one that holds only over a narrower band may show in none, which is the dose levels’ residual risk, and the factor is a placeholder, to be set by validation. The band is that at each point of an outline, so an outline whose dose varies along it, as a dose in air may, can show in parts across rows rather than whole in one. The cine strip of an RT Dose is windowed to its highest doses, which can leave a low dose outlining the skin black, and an Otsu render of a series of its planes shows one level, so only its dose levels count as showing an RT Dose’s frames for the SHA-256 of its pixel data (D-016).Each released or held instance with contours, such as an RT Structure Set, is shown as a contour sheet after the series’ previews, so that the reviewer sees a face that its contours, as the run wrote them, trace. The sheet renders the region that the contours bound as the skin-surface renders do, from the same six directions. For each Frame of Reference of its ROIs, in the order of the first ROI in each, it shows every ROI of that frame united, on cubic voxels of 2 mm however long the frame, so that a long frame’s row is taller rather than coarser, and then, where the run wrote a volume in that frame, preferring a series that the structure set references, that volume’s surface render in grey, with the edge of the united region’s silhouette in each view drawn over it in magenta. Then each item of the ROI Contour Sequence has a row of its own, in order, its ROI alone on the finer of the voxels that a united region of its own extent would have and those that keep that extent within 128 a side, but none under 0.5 mm, so that an ROI far from another is sampled as if alone, since the united region hides an ROI wholly inside another, such as a face-shaped ROI inside a box; an item without contours has a black strip, so that each row stays that of its item, and an item the same as an earlier one is rendered once. Where a ray of the frontal view, the view from behind, or a profile, which look along the axes of the voxels and so between them meet every voxel of a region’s surface, crosses an ROI’s surface more than twice, the ROI hides some of its surface behind its own, as one does with a cavity within it, such as a face-shaped cavity that
CLOSEDPLANAR_XORor keyhole contours bound within a box, or with one part behind another. Its row is then followed by a row of its cavities, the voxels that each slice of its region encloses but does not hold, rendered as a region of their own, where it has any, and by a row for each further crossing, in which each ray of those three views, and of the view from behind, shows the surface where it crosses it, into or out of the region, that many times from the viewer, so that every surface that those rays cross is shown; one surface can be split across those rows, where rays cross different numbers of surfaces before it, so a reviewer reads an ROI’s rows together. The oblique views have no rows of crossings, since their rays, which step between voxels, cross a surface falsely where they graze it. In each plane, an ROI’s region is the even-odd fill of its closed contours there, whetherCLOSED_PLANARorCLOSEDPLANAR_XOR, so that a contour within another is a hole; a plane, the mean height of contours within 0.15 mm of one another, covers the slices of voxels within half the distance to its ROI’s next plane above and below, or half the median distance between its ROI’s planes, or half a voxel where that is more, where the next is farther than twice that median or there is none. The voxel nearest each point of aPOINTcontour, or of a closed contour of fewer than three points, and nearest each point along an open or closed contour at most half a voxel apart, is filled as a mark, so that a closed contour that bounds no area is drawn as its line; and each region’s voxels extend up to a voxel below its lowest point, so that it is drawn. A mark is hidden where the ROI’s own closed contours fill its voxel, if it is a mark of a point, of an open contour, or of a closed contour that bounds no voxel, as a curve drawn within a box is; and any mark is hidden where what its slice of voxels shows, the region and every mark there, holds every voxel within two of it in the slice, as around a contour that retraces a loop within its region, one that bounds a hole that its own marks or others fill, or one in a plane that covers no slice. Those marks, with every mark of the first kinds, then have rows of their own after the ROI’s, in layers: each contour’s hidden marks lie in the first layer that holds none of their voxels and none beside one along its row or its column of voxels, so that a layer draws each contour’s marks as they would be drawn alone, and a contour’s marks the same as an earlier one’s are drawn once. Each layer has a row for each further crossing of its surface however few times a ray crosses it, but none of cavities, so that every mark is shown, in those rows or within two voxels, at most 4 mm, of the edge of what its slice shows, which the ROI’s rows draw from the front, the back, and the sides. A layer’s frontal view, view from behind, and profiles draw every voxel of it that has a neighbour along its row or its column of voxels that is not in the layer, and no other, and a set is not shown where any voxel of a layer has no such neighbour, even where an oblique view would draw it. Since a layer draws each contour’s marks as they would be drawn alone, that holds a set only where one contour’s own marks lie side by side within its region: where a line drawn back and forth over a patch, with no gap a voxel wide between its passes, covers a curve within it, where one contour retraces a cross along a row and a column of voxels, near the tip of an open contour that turns back sharply, as a V whose arms meet at 45° or less can, or where a ring only a few voxels across lies within its region, as one can at the very end of a rounded ROI. Lines that fill a hole, cross one another, or run side by side, and the outlines of planes finer than the voxels that cross one another in a slice, as a body’s and an arm’s do, or lie within one another, as near a rounded end, are each drawn in a layer of their own. A sheet shows a structure set only where every contour is of one of those five types, of finite coordinates, in threes, none above 1,000,000 mm in magnitude, with any Contour Slab Thickness and Contour Offset Vector each of one and three finite values, none above 1,000,000 mm in magnitude and no thickness below 0, and, for a closed contour of three or more points, with each point within 0.15 mm of one axial plane, and where the ROIs of each frame, as each reading below places them, span at most 2,000 mm along each axis and at most 1,000 mm from left to right and from front to back, wider than any scanner’s bore, so that each row of 2 mm voxels is at most about 1,000 pixels tall and 4,300 wide, and the sheet is at most 32,768 pixels tall, at least about 120 rows in one frame up to 510 mm long, about 103 in ten frames each with the render of a volume up to 510 mm long, about 2 fewer for each further frame with one, and about 32 rows of an ROI, or a volume’s render, 2,000 mm long, so that no viewer need scale down or refuse it; a taller sheet is drawn only until it is too tall. Contour Slab Thickness (3006,0044) and Contour Offset Vector (3006,0045), which PS3.3 retired in 2021, made a contour a slab of that thickness whose central plane is its Contour Data moved by the offset; a reader written since may ignore both, and one written before may honour either alone, so a sheet draws a structure set as each reading places it: as written, ignoring both, then, where a contour has either, with the offset alone, with the thickness alone, and with both, leaving out a reading that places every contour as an earlier one does. Each further reading has its own rows after the white gutter that starts them: the united row of each frame and its volume’s render, as written, then the rows of each item whose contours that reading places otherwise than as written. A reading moves each point of a contour by the whole offset vector, and gives a closed contour’s plane a slab along z, half its thickness below and above, that covers every slice of voxels within it, or the slice nearest the plane where none is, and draws the contour’s marks through it, at most half a voxel apart, and sweeps an open contour of three or more points within 0.15 mm of a plane, not on one line, half its thickness each way along that plane’s normal. A thickness that a reading gives a point, a closed contour of fewer than three points or on one line, or an open contour on one line or off any plane, which has no plane to be normal to, leaves the set unshown, as does one that a reading gives a closed contour whose slab along z would stray more than 0.15 mm, at either face, from its slab along the normal of the plane within 0.15 mm of which its points lie, as of a narrow contour tilted within its 0.3 mm of height and given a thickness far greater, as does a plane whose closed contours, one of which may be a hole in another, have different slabs, since their even-odd fill then has no one depth. A face that only one reading draws, as of sections written in one plane that their offsets would stack, is so shown, and a verdict on the sheet covers every reading, so the contours’ digest, which covers both attributes, binds it. Any other is listed as not previewed, ascontours-not-shown, and the pack records no SHA-256 of its contours; the pack is refused where it records a digest of contours, other than of none, without a contour sheet of that instance, or lists one ascontours-not-shownwith either, and a face review reads it the same way, so that no verdict releases contours that the reviewer did not see (D-046, D-052).Each released or held Segmentation, of Segmentation Storage or Label Map Segmentation Storage, is shown as a segments sheet after the contour sheets, so that the reviewer sees a face that a segment, as the run wrote it, traces, since a segment of the skin or body need not be labelled as one. The sheet renders each segment as the skin-surface renders do, from the same six directions, on cubic voxels of 2 mm, or of the smallest of the frames’ pixel spacing and the step of their planes’ grid where that is larger, at whole multiples of that side in the patient’s coordinates and spanning along the normal the whole cells of the first and last planes, so that none of the voxels’ side, positions, or extent depends on which frames a writer left out: first every segment united, then, where the run wrote a volume in the Segmentation’s Frame of Reference, preferring a series that the Segmentation references, that volume’s surface render in grey with the edge of the united segments’ silhouette in magenta, as a contour sheet draws it, and then each item of the Segment Sequence in order, its segment alone, followed by the rows of its cavities and further crossings, as a contour sheet’s ROI is, or a black strip for a segment that no pixel holds. Each frame is placed in the patient’s coordinates by its Plane Position (Patient), Plane Orientation (Patient), and Pixel Measures functional groups, per frame or shared. Within a frame the mask is sampled along its rows’ axis and then its columns’, each voxel along an axis holding every pixel nearest it and the pixel nearest it, so that no pixel is lost where pixels are finer than the voxels and no voxel is missed where they are coarser, even where they are finer along one axis and coarser along the other; the frames’ planes lie on a grid of their Spacing Between Slices, or of their Slice Thickness where they give no spacing, since a nominal thickness can exceed the spacing of overlapping slices (PS3.3 C.7.6.16.2.1), and each slice of voxels is covered by the plane whose cell of that grid holds it, from half a step below to just under half a step above, where a frame lies in that plane, and each plane also by the slice nearest it, so that a segment whose writer left out its empty frames, or those of every segment, as highdicom does by default, is empty there, its sheet is that of the same Segmentation with them written, and every frame is drawn where planes are closer than the voxels; a Segmentation whose frames lie in two planes or more without either measure, the same for every frame and above 0, or with a plane more than 0.01 mm off that grid, is not shown, since the planes that its writer left out cannot then be placed, nor told from planes between the grid’s. In a BINARY Segmentation, whose frames are 1-bit masks packed across frames, a pixel of 1 is in the segment that its frame’s Segment Identification names; the previews unpack those bits themselves, since pydicom 3.0 cannot decode one frame of them that does not start on a byte. In a LABELMAP Segmentation a pixel is in the segment whose number it holds, and the value that Pixel Padding Value names is background (PS3.3 C.8.20.2.4). A sheet shows a Segmentation only where it is BINARY or LABELMAP, its Segment Numbers are distinct, every frame is placed in one orientation along the patient’s axes with one spacing and, where its frames lie in two planes or more, one Slice Thickness or Spacing Between Slices, its referenced segments and pixel values are each a segment that it describes, its frames are of one time point and one stack, by its Dimension Organization Type, which is not
3D_TEMPORAL, and each frame’s Temporal Position Index and Stack ID, and no segment lies in one plane in two frames, as at two time points, since the union of two could hide the surface of either, which also refuses one plane’s tiles of a segment though they may not overlap, and its frames span no more than a contour sheet’s frame may, and where the sheet is at most 32,768 pixels tall. A FRACTIONAL Segmentation is not shown, since a face that a high fraction traces can lie within a low fraction’s region, and no one threshold would show it. Any other is listed as not previewed, assegments-not-shown, though its cine strip, its full-resolution preview, and any redaction preview are kept, and the pack records no SHA-256 of its pixel data, since only its segments sheet shows the surface that a segment traces; a segments sheet’s frames count only for its own Segmentation, not for the volume that it is drawn with. An instance is taken as a Segmentation by its SOP Class UID, or by a Modality that may be SEG, as an RT Dose is by one that may be RTDOSE, so that an image labelled SEG, which no sheet can show, is listed assegments-not-shownrather than counted as shown by its cine strip.Each released or held instance that holds a deformable registration’s grid, Vector Grid Data (0064,0009) in an item of a Deformable Registration Grid Sequence (0064,0005), is shown by five grid sheets for each grid, after the segments sheets, so that the reviewer sees a face that its displacements, as the run wrote them, trace, since a registration of two scans moves the skin and the air or couch beside it differently. The sheets are of its displacement: first, where any vector is undefined, where the transformation is defined, whose outline can itself follow the patient’s, then the magnitude of each vector; of its variation: at each grid point, the root of the sum, over the grid’s three axes, of the square of the larger of the magnitudes of the displacement’s forward and backward differences along the axis, each divided by the axis’s Grid Resolution, an axis along which neither neighbour of the point is defined adding nothing, so that a change at a single grid point or at the edge of the defined region shows rather than cancels, as it can across the skin where the magnitude does not change; and of each of the displacement’s x, y, and z components along the patient’s axes: where it is positive, then, after a white rule, where it is negative, by its magnitude, since a component’s sign can change across the skin where its magnitude does not. Each quantity is drawn as an RT Dose’s dose-levels sheet draws dose, as nested surfaces from the same six directions with the rows of their hidden surfaces, at its support, the voxels of any value above 0, and at each of 0.5, 0.2, 0.1, 0.05, and so on, of its greatest value while above its smallest above 0, but at most 40 levels, its support and the 39 highest, so that values more than some 13 decades below the greatest show only in the support, since a smooth field, such as one with a Gaussian tail, would otherwise need more levels than a sheet draws and never be shown; the maintainer chose this on 31 October 2026 over refusing such a grid, over a floor of absolute displacement, and over levels spaced over the whole range, which could leave an outline between rows. Each grid point is placed by PS3.3 Equation C.20.3-1, from Image Position (Patient), Image Orientation (Patient), and Grid Resolution, in any orientation whose direction cosines are each of unit length and orthogonal within 0.0001, oblique included, with Grid Dimensions points along each axis and the vectors running along the rows first, then the columns, then the planes. The quantities are sampled to cubic voxels along the patient’s axes, of 2 mm, or of the grid’s smallest resolution along an axis of two points or more where that is larger, at whole multiples of their side, each voxel holding the greatest of the value of the grid point nearest its centre, where that is within half a cell of it along each of the grid’s axes, and of each grid point whose nearest voxel it is, so that every grid point is drawn whether points are closer or farther apart than the voxels. An undefined vector, (NaN, NaN, NaN) as PS3.3 C.20.3.1.3 gives it, is below every level. A grid is drawn only where each of those attributes is present and of its multiplicity, its position is within 1,000,000 mm, its resolutions are finite and above 0, its dimensions are at least 1, its Vector Grid Data, of a data set read in little endian, are exactly three 32-bit floats for each point, each vector finite or undefined in all three of its components, its cells, each point’s and half its Grid Resolution to either side of it along each of the grid’s axes, an axis of one point included, span at most 2,000 mm along the patient’s z axis and 1,000 mm across, as a contour sheet’s frame may, so that it samples no more voxels than an RT Dose’s render, each sheet is at most 32,768 pixels tall, and each value and level fits 32-bit floating point, a value too small for it being drawn as the smallest above 0. An instance any of whose grids is not drawn is listed as not previewed, as
grids-not-shown, with none of its grid sheets, and the pack records no SHA-256 of its grids, so that no verdict releases it. A grid sheet lists its instance’s run position with the index of its grid, and how many grids the instance holds, which are not frames of pixel data, so it counts for no preview of them.An instance is in a high-risk category where its source’s attributes show an indicator of risk in its pixel data (D-015). It is listed with its indicators and previewed at full resolution, every frame or 16 evenly spaced, since burned-in text may be small. The indicators of a whole series, of a CT, MR, PET, or RT Dose volume, of a localizer or an RT Image, and of the head or neck, are assessed over the series’ released and held instances, since only they reach a recipient, listed with the series, and reviewed through its series’ previews; an RT Structure Set with the patient’s outline has no pixel data, so its outline’s face is reviewed through its contour sheet and the images it is drawn on, and a Segmentation’s face is reviewed through its segments sheet likewise, which shows its segments as the surfaces that they trace rather than as the masks that its other previews show; where a run under the Clean Recognizable Visual Features Option defaces those images, the structure set is cut by the same face block, or held where it cannot be (D-050, D-052).
Monochrome pixel data are rescaled by Rescale Slope and Intercept and windowed from the 0.5th to the 99.5th percentile of what each preview shows, or, where those are drawn alike, as where all but a few values are one value, from its smallest value to its largest, so that a small pattern of another value is not drawn as that one, other than a redaction preview’s full-range image (D-037), leaving out the values that Pixel Padding Value and Pixel Padding Range Limit name, which are shown black, and as no patient in a surface render, and MONOCHROME1 is inverted. Since padding is drawn as one value, a frame whose padding holds more than one stored value, which could hold an image that every preview draws black, leaves its instance’s pixel data without a digest in the pack, so that no face verdict releases them; padding of one value shows only where it lies, which the previews draw. Float Pixel Data and Double Float Pixel Data, one sample of MONOCHROME2 in 32 or 64 bits as their element has them, uncompressed, are shown as integer stored values are, taken to float32, with the padding that Float Pixel Padding Value and Float Pixel Padding Range Limit, or their double-float counterparts, name. A value that is not a number is not drawn, as padding is not, whatever its bits, since no viewer tells one from another; positive infinity is drawn above the frame’s largest value that is drawn and finite, and negative infinity below its smallest, each by those values’ range, or, where they are all one value, by its magnitude or 1, whichever is larger, so that a pattern drawn in an infinity shows even beside finite values at that extreme, where a viewer that clips to a window would show them alike; in a frame with no drawn finite value, infinities are not drawn either. A frame whose values not drawn are of more than one kind, of not a number, each infinity, and each padding value, leaves its instance’s pixel data without a digest in the pack, as padding of more than one stored value does, and a double-float frame whose values float32 cannot hold apart is listed as not previewed, as a rescale beyond float32 is. Colour pixel data of 8 bits are shown as RGB: RGB as it is, YBR_FULL and YBR_FULL_422 as pydicom converts them, and YBR_ICT and YBR_RCT as pylibjpeg-openjpeg decodes them. Compressed pixel data are decoded by the plugin pinned to their transfer syntax (Architecture item 2). Pixel data in a compressed transfer syntax that no installed plugin is pinned to decode, of another photometric interpretation, as floating-point values of another layout, or that cannot be decoded are listed as not previewed, with why, rather than left out, and so is a released or held instance whose written file the run did not hand to the pack. These are the defaults that the QC pack thread chose on 6 October 2026.
Readiness. The release report of a
public-releaserun has areadinesssection that gives each gate’s result, a reason code where it fails, and whether the run is ready, which it is only where all three gates pass (pymedphys._dicom.deidentify.readiness). The gates are checked in a second run of the same files, as the face and redaction reviews are (D-046, D-048): the first run’s QC pack is attested and its assessment recorded beside it (D-053), and the second run is given the review read from that pack and the first run’s release report. Its face review is read from the same pack (D-046), and a run given a face review and a readiness review of different packs is refused before it starts, so that the verdicts that release its instances are those that the gates check. The library’sdeidentifytakes the pack asreadiness_reviewand the first run’s release report asreadiness_report, and the private command takes them as--readiness-review DIRECTORYand--readiness-report FILE, as does the pilot command, so that the preset’s readiness can be piloted on a local export before the preset is enabled: the two are given together and apply only under the preset, so either alone, or both under another preset or a custom option set, even one of the preset’s options, is refused before anything is read, and a review that cannot be read, whose report names another pack, or whose pack is not the face review’s, stops the run before it starts, with a message that names no path. The face review must be attested and not rejected, so a run through either never reportsnot-attestedorrejected; only a review read from a pack not yet attested and given to the transform itself does. The command’s summary, and so the pilot’s, ends by saying whether the run is ready, with each failed gate’s reason code, and the library’s result gives the release report’s readiness, so that a run whose every input was released is not taken for one that is ready; the first run of a collection under the preset, given a face review with no verdicts, is not ready on any gate. Each gate is decided from the second run’s own QC pack, compared with the reviewed one, so that it covers what that run writes rather than what the first run wrote. Both review gates fail, by the first that holds, for no review (no-review), a pack not attested (not-attested) or rejected (rejected), another collection (other-collection), as the source files’ digests give it (D-053), or another policy and method (other-policy), as D-053’s policy digest gives them, which leaves out the reviewed lists and region rules, whose keyed digests differ under each run’s key: the statistical gate binds them, and the pixel and face gate holds pixel data that other rules write otherwise by its digest. The pixel and face gate then fails for a released instance in a high-risk category that the reviewed pack did not list as one among those it released or held (unreviewed-high-risk-instance), and then for a released instance with pixel data, contours, or deformation grids whose series has a verdict that its previews show a face (face-present), has no verdict that they show none (no-face-verdict), or whose pixel data, contours, or grids differ from those that the verdict was given on (face-verdict-on-other-pixel-data,face-verdict-on-other-contours,face-verdict-on-other-grids), in that order whatever the instances’ order (D-046); an instance whose digest is unknown counts as one that differs. A passing statistical gate whose assessment covers faces reconstructed from the images stands in for the verdicts, never for the review of high-risk instances. The attestation gate then fails where the releaser did not accept the residual risk (residual-risk-not-accepted), for a released instance whose source file the reviewed run did not release or hold, so that its series’ previews could not have shown it, an identical copy of one that it did being the same file (unreviewed-instance), and for a retained string of a released instance that the reviewed pack does not list (unreviewed-retained-string). The statistical gate is D-053’s, given the distinct subjects, by Patient ID with its issuer, of the instances that the run releases, those that name none counting as one, as the run groups them for its residual search, and the reviewed ROI names and descriptors lists that the run read, with the reviewed region rules that it applied. The gates are independent: each gives its own reason, and a run without a review fails each of them, as does apublic-releasereport given no readiness. Under any other policy the section is null, and the run refuses a review. The report names the reviewed pack and the assessment by their references alone.A ROI Name that automatic cleaning writes in the vocabulary’s spelling is a cleaned value, not a retained string (D-009), so the human review gate’s review of every distinct retained string does not cover these renames, and
public-releaseadds no review of them. A rename writes a name of the vocabulary, never source text, and a name that echoes a known patient or other person identifier goes to review instead of being renamed (D-009), so the gate’s purpose, that a person sees every source string that the release keeps, is already met. A wrong rename is an error of utility, not a disclosure, and the confidential QC pack lists every rename for anyone checking utility.
Rationale. MIDI §1.15.2.2 describes 0.09 as a common choice and 0.05 for more sensitive collections. Sections 1.15.1.1 and 1.15.1.2 show that such a number is meaningful only with a group size, reference population, threat model, and choice of maximum or average risk, and that public releases are assessed on maximum risk with attack assumed certain. The statistic covers only the modelled disclosure channels, so it cannot replace pixel review or human QC, or establish legal anonymity. Device identity is omitted whatever the assessment finds because it discloses through channels that an assessment of patients’ quasi-identifiers can miss: naming the institution shrinks the population that a subject is drawn from, a machine’s name with the weekday and time of day that Modified Dates keeps can place a treatment in an insider’s schedule, and a kept Source Serial Number links subjects and discloses the differences between their offsets (D-007). The Basic Profile keeps Manufacturer, Manufacturer’s Model Name, and Software Versions, so the preset loses which unit acquired an image, not what kind of unit. The surface renders were added when the maintainer chose on 12 October 2026 to implement the Clean Recognizable Visual Features Option by attestation and then by CT defacing, since a recognition system matches a reconstructed skin surface, which neither a cine strip nor a frontal maximum intensity projection shows. A volume whose axes do not lie along the patient’s was first shown by its cine strip alone, since a projection along an oblique axis would superimpose what a frontal view keeps apart, so a verdict could release at most the 16 slices of its strip, and a gantry-tilted head CT or an oblique MR series was in effect withheld. When the maintainer chose on 1 November 2026 to support gantry-tilted and oblique head CT under the option before the first release, such volumes were sampled to voxels along the patient’s axes by one shared sampler, which gives the grid’s voxels exactly on a volume whose axes do lie along them, so that their projection and renders are frontal like any other’s and draw every slice. Their projection’s voxels are bounded at \(2^{24}\), since a head’s 0.45 mm pixels would give about 117 million voxels, which took about 13 s to project for one series of 60 slices when measured, where about 0.9 mm voxels took about 2 s; the 2 mm renders are what a verdict on a face relies on, and the projection draws every slice at any voxel size, however coarse. The view from behind was added so that a surface facing the back is seen as one facing the front is, and not only edge on from the sides, as a face would be in a volume whose stated orientation puts it at the back, and so that the edge of a contour sheet’s slice that faces the back is drawn. The renders were first sampled to keep each axis within 256 voxels, so a volume more than 510 mm in extent was rendered coarser than 2 mm, about 7 mm for a whole-body CT 1,800 mm long, coarser than the render of a head that a reviewer’s verdict on a face relies on; they now keep 2 mm, within the bounds of a contour sheet’s frame, and a volume beyond them is held beyond its cine strip, failing safe, since no scanner’s bore is 1,000 mm across. The per-series face verdicts were added for the same option, so that a reviewer’s judgement of each series is recorded with the exact source files it covers. The contour sheets were added for D-052’s condition that the option not be enabled until the reviewer sees each structure set’s contours as written, drawn with its images: a row for each ROI item as well as each frame’s union, since a union hides an ROI wholly inside another, which a verdict would otherwise release unseen, and points and open contours drawn as marks rather than leaving their sets unshown, since clinical sets commonly carry markers such as an isocentre’s point. An ROI also hides from its own row any surface behind its own, as a box hides a face-shaped cavity that its own contours bound, so such an ROI has rows of its cavities and of each further crossing of its surface; listing such sets as not shown instead would hold every ROI of paired organs, a body with its arms, or a vertebra with its canal, and holding only contours nested in a plane would miss a keyhole contour’s cavity and a part hidden behind another. Its region likewise absorbs a mark on a voxel that it fills, such as a curve traced within it, which would otherwise bind its digest to lines that the reviewer did not see, so such marks have rows of their own; the marks of a closed contour that bounds a voxel lie on the edges of what its slice shows, except where it runs within that region, bounds a hole that marks fill, or lies in a plane that covers no slice, so only its marks two voxels or more within what the slice shows join those rows, which would otherwise draw every ROI’s outline again. Those rows draw their marks as regions, which cannot show a mark that they hold within themselves, so they show every crossing that the rays of the frontal view, the view from behind, and the profiles make, and a set is held rather than shown where a voxel of a layer has no neighbour along its row or its column that is not in it, since no ray of the frontal view or a profile then crosses into or out of the layer there; a test of the marks’ depth within their own rows, as for those within the region, would miss marks that cover a curve while leaving gaps a voxel wide between them. With all of an ROI’s hidden marks in one layer, as first made, a contour’s marks merged with those beside them, so that test also held sets whose rows would draw each contour alone: three or more lines side by side, two lines that cross along a row and a column of voxels, a body whose outline crosses its arms’ in planes finer than its voxels, and a rounded end that is blunt for its voxels in planes about 0.3 of its voxel apart or finer, where the rings of several planes lie within one another in a slice, such as a body 400 by 250 by 600 mm, of 2.35 mm voxels, at all of 16 offsets in planes 0.7 mm apart, and ellipsoids the size of a liver (220 by 160 by 180 mm) and the lungs (300 by 180 by 260 mm) in planes 0.5 mm apart. Each contour’s marks in a layer where no other’s lie beside them are drawn as they would be alone, and a curve that lines cover, or a hole’s outline that they fill, is shown in a layer of its own rather than held. Every one of those sets is now shown: the body in planes 0.5 to 1.25 mm apart, and the liver, the lungs, and an ellipsoid 300 by 200 by 480 mm, each at four offsets; the body in planes 0.625 mm apart has 2 layers of hidden marks, and its sheet is 4,232 pixels tall; of two draws of 108 rounded ROIs 40 to 300 mm across, 27 in each of planes 0.5, 0.625, 1, and 1.25 mm apart, one is held: in planes 0.5 mm apart, an ellipsoid 200 by 140 by 160 mm whose lowest plane lies 0.023 mm above its end, so that the ring there, about 3 by 2 voxels across, lies side by side with itself within the slice’s region. A set whose hidden marks fit one layer is drawn as before. Counting the oblique views, which can draw a voxel that the frontal view, the view from behind, and the profiles do not, was measured instead and is left out: with each contour drawn as alone, it would add only where one contour lies side by side with itself, as at the tip of a sharp V. A V within its region whose arms meet at 45° was held at 2 of 24 placements over voxels of 0.5 mm, at 30° at 9, and at 20° at 14, and at 60° and 90° at none; counting the obliques’ first hits would show the 2 at 45° and leave 5 held at 30° and 9 at 20°, and would draw a cross that one contour retraces, but not a zigzag two voxels tall. Holding such sets fails safe, and splitting a contour into pieces that each draw would show a face’s outline only in pieces. A mark up to two voxels within is left to the edge, since the contours of planes that cover no slice, between those of a smooth outline, lie there without showing anything that the edge does not; so a part of a contour that runs within two voxels of its slice’s edge, at most 4 mm, is shown only as that edge, which a view looks at from the front, the back, or a side. Near a rounded end, such as the top of a head or the ends of a body, an outline can shrink by more than two voxels from one such plane to the next, so planes finer than the voxels there give rows of hidden marks: in planes 1 mm apart over voxels near 2 mm, a head to its top or an ellipsoidal body 480 mm long has 11 rows, 4 of them of hidden marks, where planes 3 mm apart give only its own row. No fixed depth avoids those rows, and a narrower test, such as of a mark’s depth within its own plane’s region, would miss a notch that such a plane cuts into its outline, where a face could lie, so the rows are kept. The contours as received are not drawn, since a sheet of them would put back in the pack the face that the run removed, and a verdict covers only the contours written. On synthetic sets of an elliptical outline 180 by 216 mm across and about 200 mm long, in planes 2.5 mm apart, and ROIs of random elliptical sections 6 to 96 mm across and 5 to 60 mm long, centred within 50 mm of its axis, none of whose ROIs hides its own surface, and no volume to draw them on, a sheet of 60 ROIs is about 4,400 pixels tall by 870 wide and 0.3 MB as a PNG, made in about 2 s, and one of 150 ROIs about 10,600 by 870 pixels and 0.8 MB, made in about 5 s. A sheet is drawn only until it is too tall, and its height without rows of cavities or further crossings is found before any of it is drawn, so most sets over the bound are held without drawing it. A closed contour in another plane is not drawn, since the slices of voxels would cut its region edge on, so its set is held rather than shown in part.
Tests. Subject versus instance counts; longitudinal and prior-release linkage; missing model, assumptions, or coverage; threshold boundaries; failed or stale assessments; and independence of the three gates. Contour sheets: closed, open, and point contours are read with the frames and series that the set references, each ROI taking its own frame or else the set’s only one; a sagittal or tilted closed contour, an unknown or missing type, a value that is not finite or too far, a Contour Slab Thickness below 0, not finite, too great, or of two values, a Contour Offset Vector of two values, not finite, or too far, an offset that takes a point too far, a thickness on a point, a two-point or collinear closed contour, a straight line, or a non-planar line, a thickness on a closed contour tilted within its height whose slab along z strays more than 0.15 mm from its slab along its normal, while a rounded axial contour and one tilted less are drawn, a plane whose outline and hole have different thicknesses, Contour Data not in threes or absent, or ROIs of one frame spanning more than 2,000 mm, or more than 1,000 mm from left to right or from front to back, leaves a set unshown, while ROIs spanning exactly 1,000 mm across are shown; each reading of the slab attributes that places a contour otherwise is drawn, none where both are absent or zero, two with either alone, and four with both, moving a contour by the whole offset, a closed slab filling every slice within it, its marks too, a slab between slices filling the nearest, a hole through a slab of its outline’s depth, and an open contour swept through its depth, while an offset alone still moves a point or a line; a sheet draws each further reading after a white gutter with its frames’ united rows and the items it changes, and is bound by them all; a head of sections written at z = 0 and moved by their offsets is drawn in its offset reading as the head written at its heights, and a head of 3 mm slabs shows its nose in each reading; a verdict of absent releases a slab set that its sheet showed, and holds as
no-face-verdict, with no contour digest, one whose thickness is below 0 and one of a tilted narrow slab; a contour within another of its ROI is a hole for either closed type; one ROI’s planes never empty another’s slices; a gap of more than twice the planes’ spacing is left empty; points and lines are drawn as marks; an ROI alone is sampled finely, and no coarser for an ROI far from it; a frame’s united row, and an ROI more than 510 mm long, are drawn on 2 mm voxels, and a sheet is the same however many slices are rendered at once; every point of an ROI, the lowest of many planes, and an open contour’s lower end are drawn; a closed contour that bounds no area is drawn as its line, and marks are taken along a segment a whole number of steps long; a head’s nose shows in the renders of its contours and not of contours cut, and the same contours always give the same PNG; an ROI enclosed by another has its own row; a face-shaped cavity that one ROI’sCLOSEDPLANAR_XORor keyhole contours bound within a box, which the box’s own row hides, has a row of its own and shows in the rows of further crossings, and two parts of one ROI, one behind the other, give a row for each further crossing; open curves, a point, a point just inside an edge, a closed contour that bounds no area, and two identical closed contours within their own ROI’s box, which the box’s rows hide, have rows of their own that tell different curves apart, and a line above the box has none; a box contour that also traces a loop within the box twice, or a spur into the box and back, has rows that tell a square loop from a circle and a straight spur from a bent one, and so do, in a slab of planes finer than its slices, a slit a voxel wide and a hole in a plane that covers no slice; lines that fill a box’s hole, or that cover a curve within it with gaps a voxel wide between them or in bands four voxels wide, are drawn in layers that tell a square hole from a circle and one curve from another, and so are lines that cross along a row and a column of voxels or lie three side by side, and the rings near the ends of an ellipsoid the size of a liver in planes 0.5 mm apart, while contours whose voxels touch only diagonally, and a contour repeated, share a layer; a box whose curve one line drawn back and forth over it covers, or within which one open contour retraces a cross, has no sheet; over random ROIs with random points, lines, and retraced loops, the frontal view, the view from behind, and the profiles cross into or out of each region at every voxel of its edge in its slice and no other, some layer holds each contour’s hidden marks and draws them as alone, and a set is shown exactly where its layers’ rows draw every voxel of them; a head to its top in planes 1 mm apart has rows of its hidden marks, and a sheet; ordinary outlines, of a head, a box, and that slab, hide no marks; each crossing of a surface is found in order along a ray, up to the ray’s end; a volume 1,000 mm long is rendered on 2 mm voxels, and one more than 2,000 mm long or 1,000 mm across, from left to right or from front to back, is neither sampled nor rendered, and a CT series that wide has only its cine strip, and pixel data’s digests only for the slices that it shows; the view from behind shows a head’s ear on the viewer’s left, mirrors the frontal view of a head symmetric from front to back, and hides its nose, and only it and the profiles show a bump on a box’s back; views and crossings are the same however many slices are rendered at once; a dose level’s rows of further crossings that would not fit are neither drawn nor found; a dose sheet’s levels are separated by grey rows and the rows within a level by black; a grid’s sheet, or a plane’s map, of one level more than the bound is not drawn, before any level is, and one at the bound is, and a series of planes whose scalings differ by 20 decades has no dose levels; an RT Dose whose dose levels are not drawn, whatever the cause, is listed asdose-levels-not-shownbeside its cine strip, its frames are still shown by any other preview, and a cleaned one keeps its redaction previews and can be given a verdict; each frame has its own united row and each item its own, with a black strip for an item without contours; a sheet is drawn with the CT series that the set references, not another in its frame, with the outline in magenta in that row alone, and without a CT row where none is in its frame; every structure set with contours has a sheet, whatever its risk; a sheet over its tallest is not given, and is drawn only until it is too tall, and an ROI whose layers would take more of its height than is left has none drawn, while one whose own rows would has neither its rows drawn nor its crossings or hidden marks found; a set with a contour not drawn, or whose sheet is over the height bound, even by the rows of a cavity alone, is listed ascontours-not-shownwith no contours’ digest, while a set without contours keeps the digest of none; the contours’ digest changes with a Contour Offset Vector or Contour Slab Thickness; a pack, and a face review reading one, refuse a contours’ digest without a sheet, and a pack refuses a set listed as not shown with a sheet or a digest; even-odd filling matches an independent polygon library on random polygons, holes, vertices, and horizontal edges; and in two runs of a structure set alone, a verdict of absent releases one whose contours were shown, and holds one with a sagittal contour, or whose sheet is over the height bound, asno-face-verdict; and the pack records the SHA-256 of pixel data only where its previews show every frame: an instance with more frames than its cine strip or its full-resolution preview shows, a series that forms no volume beyond the frames of its cine strip, and Float Pixel Data, listed as not previewed, have none, while every slice of a volume, shown by its projection and surface render, and every frame of an instance whose frames are all shown, have theirs; a file without pixel data keeps the digest of none; Pixel Data holding more than their frames have none; an RT Dose’s dose levels list every frame of grids of 30 and 12 frames, of a series of planes, of two planes, and of one, and of a grid labelled CT, and a grid without them, unscaled, scaled by 0 or below, rescaled, oblique, with uneven offsets, or longer than its frames, or a series of planes one of which is unscaled, has none though its cine strip or Otsu render lists every frame; the dose levels run from the support to half the greatest dose, no two neighbours, nor the lowest and the smallest dose, more than 2.5 apart; the support of a grid is the head that a CT render shows, and a hot spot alone is above it; a nose at 12 mGy beside a 1 Gy core shows in the support where air is set to zero, and in the 5 and 10 mGy levels where air has 3 mGy, and never in the 5% level; planes with their own scaling render as the grid of the same doses; a lone plane is mapped grey by its levels; a signed grid, a signed lone plane, and a series of planes one of which is signed list every frame; a signed grid shows its ladder above 0, then, after a white rule, its ladder below 0, the head at -1 Gy drawn below 0 as a CT render draws it; a head at +12 mGy in air at -12 mGy, the same magnitude everywhere, shows its face in the support above 0 and in the cavity of the support below 0; a signed grid with no dose below 0 is the unsigned grid’s sheet, a white rule, and an empty support; each ladder runs down its own doses; a dose below 0 on a slice between voxels is drawn; a dose below 0 that its scaling loses is refused; a signed plane is mapped above 0, then below between white columns; a signed sheet’s height bound counts both ladders, and each ladder’s level bound refuses it; a grid that cannot be placed or levelled has a cine strip only; a block in a slice of a volume whose slices are closer than its projection’s pixels and its render’s voxels, which nearest-neighbour sampling alone would skip, changes both; and the pack, and a face review reading one, refuse a pixel data’s digest unless previews that could show a face list its frames from the first with none missing, or for an instance listed as not previewed; a face review holds pixel data with more frames than its pack showed, and a run given one holds such an instance; a 12-frame CT instance labelled RTDOSE is not shown; an instance is an RT Dose by its SOP Class UID, or by a Modality of RTDOSE in any case, of several values (soCT\MRis one too), unreadable, not text, or with a character outside printable ASCII such as a leading NUL or a letter outside ASCII, and not by a missing or empty one; a face review holds an RT Dose with pixel data unless its dose levels showed every frame, and so always where it gives none, while one of dose-volume histograms alone needs none, and a run given a review that binds every frame of a dose grid, or of a CT instance labelledRTDOSE,rtdose,RTDOSE\CT, orRTDOSEafter a NUL, through other previews, or through dose levels of fewer frames, holds it, and releases it through dose levels of every frame; and in two runs, a verdict of absent holds asface-verdict-on-other-pixel-dataan instance beyond its cine strip, one longer than its frames, an unscaled grid, a grid longer than its frames, and a series of planes one of which is unscaled, and releases an instance whose every frame was shown, dose grids of 30 and 12 frames, a series of single-frame RT Dose planes, and a lone plane. Grid sheets: a grid’s vectors are read along its rows, then its columns, then its planes, and every grid of every item in order; a grid is refused for each attribute missing or of another multiplicity, direction cosines not of unit length or not orthogonal, a position too far, a resolution not finite or not above 0, a dimension below 1, Vector Grid Data of another length, a vector partly undefined or infinite, data read in big endian, cells spanning more than 2,000 mm along z or 1,000 mm across, also along an axis of one point in each of five orientations, without stopping the pack, and a sequence that cannot be read; in five orientations, oblique included, each grid point is drawn at the voxel nearest it, each voxel of a coarse grid takes the point that an inverse of Equation C.20.3-1 finds nearest it, and a fine grid leaves no voxel within it undrawn; the variation takes the larger one-sided difference and leaves out undefined neighbours; a ladder is the dose ladder cut to its highest levels; the sheets of an analytic head’s displacement show its nose, which a field cut ahead of the face does not, and the same grid gives the same PNGs, the displacement’s frontal view is the head’s silhouette, an undefined region adds a ladder, each component’s sign has its own ladder, a sheet taller than its bound is not drawn, and a value too small for a voxel stays above 0; a registration is previewed by each sheet of each of its grids, after the segments sheets, high-risk or not, one any of whose grids cannot be drawn, or would be too tall, is listed asgrids-not-shownwith no sheet, and one without a grid has none; the grids’ digest changes with each grid’s orientation, position, dimensions, resolution, vectors, and order, not with the frames that the registration names, is that of none for a data set without a grid, and is not taken of grids that cannot be read; a pack records it only where a sheet of each kind shows each grid, each sheet shows one grid of one instance once, with one count of grids, and an instance listed asgrids-not-shownhas neither a sheet nor the digest; and the reader takes the digest only where every sheet shows each grid, with its count, and judges no file by grids that the pack lists as not shown. Segments sheets: a Segmentation of either SOP Class is an indicator whatever its segments, and names the head or neck by Body Part Examined or by a segment’s Anatomic Region or Segmented Property Type, as a parotid gland’s, while a Surface Segmentation is not assessed and an unreadable Segment Sequence is unreadable evidence; a sheet is refused for a FRACTIONAL or SURFACE type, repeated Segment Numbers, a frame count other than its frames, a frame without a position, a BINARY frame without a listed segment, a tilted or mixed orientation, a spacing of 0, a coordinate too far, or frames spanning more than 2,000 mm; in each of five orientations, off centre with rows 0.8 mm and columns 1.2 mm apart, each pixel is drawn at the voxel nearest the position that PS3.3 C.7.6.2.1.1 gives it; a line of pixels 0.5 mm apart keeps every voxel along it, a block of pixels 5 mm apart fills its voxels without holes, and a ribbon one pixel wide along the coarse axis of pixels 0.5 mm by 5 mm apart, in either order, is drawn without gaps; a BINARY or LABELMAP segment in one plane twice, as a head and then a box that encloses it, is refused, and so is that box 0.1 mm above the head’s planes, whether labelled3D_TEMPORAL, by two Temporal Position Indices, by two Stack IDs, or not at all, while frames of different segments in one plane, and frames labelled with one time point and one stack, are drawn; a head’s nose shows in its BINARY and LABELMAP segments’ renders and not when cut, and the same segments give the same PNG; a segment within another has its own row, one with a cavity has rows of what it hides, and one that no pixel holds a black strip; a segment’s left-out frames are empty, and so are the 19 empty frames left out between two plates 20 mm apart on a grid of 1 mm, and the three left out between plates 4 mm apart of 5 mm Slice Thickness and 1 mm Spacing Between Slices, each of whose sheets is that of the same Segmentation with them kept, as is that of plates 4 mm apart, of pixels 0.5, 3, 4, or 8 mm apart, with or without the empty frames between and three below them, whose voxels are 2 mm and keep an empty slice between the plates; and plates in frames 10 mm apart, one or two of seven planes, BINARY or LABELMAP, in each of five orientations, fill their whole cells of five 2 mm slices, and give the same sheet, whether or not the empty frames beyond them are written; frames in two planes without a Slice Thickness or Spacing Between Slices, or with one of 0, below 0, or not a number, are refused, while frames in one plane need neither, and the spacing is taken, or the thickness where there is no spacing; plates 20 mm apart on a grid of 3 mm, and frames 1 mm apart, or plates 4 mm apart, of 5 mm Slice Thickness and no spacing, are refused; a label map pixel of no listed segment, too few or too many frames, or a sheet over its tallest, gives no sheet; a sheet drawn with the CT series in its frame has magenta in that row alone, lists the Segmentation’s frames and then the series’, and the Segmentation counts as shown; a FRACTIONAL Segmentation, one with an unlisted value, one with a segment in one plane twice or at two displaced time points, or one whose sheet is too tall is listed assegments-not-shownwith its cine strip kept and no digest, even where its cine strip shows every frame, as is a 12-frame CT instance labelledSEG,seg, orSegwith padding; an instance is a Segmentation by either SOP Class UID, padded or not, or by a Modality of SEG in any case, of several values, unreadable, not text, or with a character outside printable ASCII, and not by a missing or empty one, another modality, or the classes of Surface Segmentation and Height Map Segmentation; a face review holds a Segmentation with pixel data unless its segments sheet showed every frame, and so always where it gives none, takes a sheet’s frames for its own Segmentation alone, and holds one that is also an RT Dose unless its dose levels showed every frame too; a run given a review that binds every frame of aBINARYorLABELMAPSegmentation, or of a CT instance labelledSEGorSEG\CT, through other previews, or through a sheet of fewer frames, holds it, and releases it through a sheet of every frame; a second run given a verdict on aBINARYorLABELMAPSegmentation’s sheet releases it, and one given a verdict on aFRACTIONALone of 15 frames, which its cine strip shows each of but no sheet, holds it asface-verdict-on-other-pixel-data; and a cleaned one keeps its redaction previews and can be given a redaction verdict; and 1-bit frames that do not start on a byte are decoded as the whole array is. Readiness: every gate passing, and each failing for each of its reasons alone while the others pass; a run without a review or assessment; the gravest face reason first; an instance without pixel data or contours needing no verdict; an assessment of facial reconstruction standing in for the verdicts only where its gate passes, and never for high-risk review; retained strings and high-risk instances needing review only where released; the review read from a pack and a report of that pack, with no value in its repr; the section’s checks and its Markdown; a review refused under another policy, or beside a face review of another pack; and two runs of the synthetic collection under the preset, the first given no face verdicts and the second, given the verdicts on the first’s pack, ready. Through the command line and the library alike, and through the pilot command for a ready run and its arguments’ checks: a first run under the preset, given the attested pack of a Basic Profile run with no face verdicts, which is not ready on any gate and says so; second runs given its pack, attested and assessed, that are ready, releasing both subjects’ images and plans and the structure set’s contours, and that fail only the statistical gate for no assessment, a maximum risk above the threshold, and a subject fewer or more, only the attestation gate for a residual risk not accepted, every gate for other files and for TCIA’s list of safe private rules, only the statistical gate for a reviewed-names list with one more decision, and it and the attestation gate for one that now keeps a name that the reviewed run mapped; a pack not attested or rejected stopping the run as its face review; a review of another pack than the face review, of a pack that does not exist or is empty, with a report that does not exist, is not JSON, or is of another run, or with an assessment that cannot be read, refused naming no path and creating nothing; the arguments refused alone, under another preset, and under a custom option set of the preset’s options, before anything is read, and the preset not enabled refused before the review is read; and a published readiness read by its codes, and one that cannot be read reported as unknown, naming nothing.
Multi-frame volumes: the frames of an Enhanced CT, Legacy Converted Enhanced CT, Enhanced PET, or Enhanced MR instance, placed by per-frame or shared functional groups, are projected and rendered as the same slices written as single-frame instances, in any frame order, axial or coronal, and each frame is rescaled by its own group; CT frames whose Rescale Type is other than HU or absent from their group, and CT Image instances of other units, are rendered at Otsu’s threshold; single-frame and multi-frame instances of one series, and two multi-frame instances of one series with the same Stack ID and Temporal Position Index at interleaved positions, are volumes of their own, while two instances of one Concatenation form one, and an instance of two Dimension Organization UIDs forms none; each time point or stack of an instance is a volume of its own, and frames at one position of one time point form none; a frame without a group, with one in both sequences or of two items, with an unreadable slope, or too few per-frame items, leaves the instance in no volume, while frames of an oblique orientation, offset within their plane, form one; an Enhanced CT whose finite slope and intercept overflow float32, an Enhanced MR whose slope float32 rounds to 0, or whose intercept rounds its levels together, and single-frame CT slices that overflow are listed as not previewed, while a slope of 1e30 that float32 holds is shown; contour and segments sheets are drawn on a multi-frame volume as on its slices; and a defaced Enhanced CT instance of more frames than its cine strip shows is released on a face verdict on its previews. Tilted and oblique volumes: on stacks whose axes lie along the patient’s, head first, feet first, prone, coronal, sagittal, and in slices closer than the voxels, the sampler’s surface, at the CT level, Otsu’s with padding, and dose levels, is the grid’s, voxel for voxel and in every view, with slices added in any order; a lattice cut into slabs of as few as one voxel samples each voxel, and each slice’s nearest and crossed voxels, as one sampler of the whole lattice, and renders the same image; the analytic head with a gantry tilt of 0.5°, 15°, and 30°, sheared by 15°, turned 10° about the superior axis, and turned obliquely about two axes, is rendered at the CT level with no more voxels differing from the head as it lies, at their centres, than twice the untilted head’s; a gantry-tilted head CT written as CT Image files is projected and rendered, each preview listing every slice, its render that of the head as sampled, and a verdict can release every slice; a tilted projection has the head up and the patient’s right on the viewer’s left; in 30 tilted slices 0.4 mm apart, some nearest no voxel, a slice that alone holds tissue is drawn by both the projection and the render; an oblique RT Dose grid is shown by its dose levels, every frame listed; a tilted stack longer than 2,000 mm is neither projected nor rendered; contours are drawn with the surface of a tilted series in their frame; and stacks rotated 30° or 0.1° about the superior axis, oblique, offset within their plane, or sheared, are projected and rendered whole, while one whose rows and columns are 0.01 off perpendicular forms no volume.
D-018: Published benchmark results#
Decision.
For each release of the engine, publish results against the NCI MIDI validation resources as separate metrics rather than a single score, recording versions and supported coverage. Each implementation pull request adds its own tests and traceability, and M6 consolidates the evidence for the first supported release. Releases that change only documentation or legacy code claim no engine results.
Use the MIDI-B collection, with its synthetic and curated datasets, answer keys, and mapping files (doi:10.7937/cf2p-aw56), and the Pseudo-PHI-DICOM-Data collection (doi:10.7937/s17z-r072), both licensed CC BY 4.0, with the NCI validation script (Apache-2.0).
Benchmark runs download the collections. Tests may use small subsets cached through the PyMedPhys Zenodo data store, with attribution, the licence, and a note of changes. The validation script’s repository is not copied into PyMedPhys, because it also bundles third-party executables.
The benchmark harness is run on the TCIA collections only on the maintainer’s own machine, not in automated sessions, as the maintainer decided on 6 October 2026.
Report results per answer-key category, and document each category where PyMedPhys’s policy deliberately differs from the answer key.
Rationale. Separate, versioned metrics let users judge performance for their own data and coverage. The validation manual states that many answers follow TCIA’s original curation of each source collection rather than strict DICOM requirements, so an aggregate score would penalise deliberate, conformant differences. CC BY 4.0 permits redistribution with attribution, and the collections are too large to keep in the repository.
Tests. The benchmark workflow reproduces the published results, and cached subsets carry their attribution.
D-019: No deprecation before a released replacement#
Decision.
Disclose the legacy tools’ limitations now with warnings that are not deprecations and promise no removal. For experimental pseudonymisation, these are a
UserWarningsubclass in the library, a standard-error notice on the command line, and a banner in the app. Forpymedphys.dicom.anonymise, they are corrected documentation and docstrings, aUserWarningsubclass from the library function, and a standard-error notice on the command line.Deprecate a legacy interface (library, command line, or app) only once a released replacement covers its use and migration guidance is published, which is no earlier than the first supported release (M6). That release replaces the library and the command line, not the app (Scope), so the legacy pseudonymisation app stays, with its limitation banner, until the new app ships.
Keep each legacy interface for at least one full minor release with deprecation warnings, then remove both in the same release. Record exact versions in the release notes when they are scheduled.
Until removal, change the legacy tools only to stop them disclosing identifying information or to prevent harm to data, such as silently altering or losing source files. List other defects among the limitations in the user guidance instead of fixing them.
Rationale. Deprecating before a replacement exists would leave users nowhere to go and, if the work stalled, would make the warning permanent noise. If the replacement is not delivered, both legacy interfaces remain available with their documented limitations. Other fixes to the legacy tools are spent on code with a limited life, and can change behaviour that users rely on, as a new pseudonym format would; disclosure and data-safety fixes protect people and data until the replacement is available, which justifies that cost.
Tests. Limitation warnings are not
DeprecationWarnings and mention no removal; each public call warns once; and the command-line and app notices appear. Once deprecation starts, the deprecation warnings are tested and the migration guide is published.
D-020: Compound actions from the strictest Type#
Decision.
A compound action of Table E.1-1a (X/Z, X/D, Z/D, X/Z/D, or X/Z/U*) is resolved from the strictest Type that the instance’s IOD gives the attribute at that place in the data set, across every definition of it there (D-001). Type 1C counts as 1 and 2C as 2, and modules of conditional (C) and user-optional (U) usage are included, so no condition is evaluated.
The action is then D for Type 1, Z for Type 2, and X for Type 3. Where the compound action does not offer that action, the next of X, Z, and D that it offers applies, as the definitions in Table E.1-1a imply: X/D gives D for Type 2, as for RT Plan Date (300A,0006) in the RT Plan IOD, and Z/D gives Z for Type 3. In X/Z/U*, U, the replacement of the instance UIDs that the sequence contains, takes the place of D.
X/Z on an attribute that is Type 1 or 1C at its place writes D’s dummy value, as a plain Z there does, which the maintainer decided on 1 October 2026. Table E.1-1a defines Z as “replace with a zero length value, or a non-zero length value that may be a dummy value and consistent with the VR”, so this is the Z that X/Z offers, with a non-zero-length dummy value, and the conformance statement describes it so. In 2026d, no attribute with X/Z is Type 1 or 1C anywhere in the first supported release’s 61 IODs. Of the other generated IODs, only Referenced Study Sequence (0008,1110) is, in three sequences of the RT Patient Position Acquisition Instruction and RT Physician Intent IODs; it is a sequence, which has no generic dummy value, so it needs a reviewed rule, and until one exists its instance is sequestered (D-021).
An attribute that the IOD does not define at that place is treated as Type 3, so it is removed, or emptied under Z/D.
The Type also decides how a plain X, D, or Z is applied; the maintainer decided these rules on 1 October 2026:
Where Table E.1-1 gives a plain X, the attribute is removed, as Table E.1-1a defines X, whatever its Type. Where the IOD requires it at that place, by its strictest Type as above, the engine keeps the output valid by also removing the innermost sequence that encloses it and that the IOD makes Type 3 at its own place, with everything in that sequence, and sequesters the instance where no such sequence encloses it. This includes an X that applies under Clean Descriptors where descriptor cleaning applies the Basic Profile’s action (D-009). Two attributes need neither. Where Overlay Data (60xx,3000) is removed, every attribute of its repeating group is removed with it, since, of the first supported release’s IODs, only CT Image, MR Image, Positron Emission Tomography Image, and Nuclear Medicine Image include the Overlay Plane Module, each as user-optional (U), and Nuclear Medicine Image also includes the Multi-frame Overlay Module, user-optional too, whose attributes are of the same group. ROI Interpreter Sequence (3006,004E) is removed, as the table says. PS3.3 Table C.8-44 makes it Type 1C: “Required if ROI Creator Sequence (3006,004D) is present in the Structure Set Module, and the person or device performing the interpretation differs from ROI Creator Sequence (3006,004D). May be present otherwise.” Table E.1-1 removes ROI Creator Sequence too, so that condition never holds in the output. Two places depart from Table E.1-1’s X. Requested Procedure ID (0040,1001), Type 2 in Referenced Request Sequence (0040,A370), which is Type 1C at the top level of a Structured Report and required where the report was made for a request, is emptied there (Z) where its removal would sequester the instance, which the maintainer decided on 26 October 2026 (06:45 UTC); without it every report made for a request would be sequestered under every policy. Source Manufacturer (300A,0216), Type 2 in Recorded Source Sequence (3008,0100), which is Type 1 at the top level of RT Brachy Treatment Record, is emptied there too, which the maintainer decided on 31 October 2026 (22:27 UTC), since every conforming record holds it and no Type 3 sequence encloses it, so without it every RT Brachy Treatment Record would be sequestered under every policy that does not select Retain Device Identity, which keeps it; Table E.1-1’s X/Z empties Source Serial Number (3008,0105) in the same item. In each, a zero-length value discloses nothing that removal would not.
The basis is Table E.1-1a, which defines X as removal and gives an alternative by Type only through its compound actions, such as X/Z and X/D, and E.1.1’s Note, which makes it “the responsibility of the de-identifier to ensure that this process does not negatively affect the integrity of the Information Object Definition”. Removing an optional sequence that encloses the attribute does both: the attribute is removed, as the table says, and the IOD stays valid, so the instance keeps an exact Basic Profile claim. For example, Responsible Person (0010,2297) is Type 2C in the Patient Module, “Required if the Patient is a non-human organism. May be present otherwise.” Since conditions are not evaluated, it counts as required there, and no sequence encloses it, so an instance that has it is sequestered, as is one with Responsible Organization (0010,2299); both are rare outside veterinary data.
In 2026d, the first supported release’s IODs have ten attributes with a plain X that the IOD requires and that no removed sequence encloses: Series Description (0008,103E), Type 1 in Source Series Information Sequence (3006,004C) of the RT Structure Set IOD; ROI Interpreter Sequence, Type 1C in RT ROI Observations Sequence (3006,0080) of the RT Structure Set IOD; Responsible Person (0010,2297) and Responsible Organization (0010,2299), Type 2C in the Patient Module of each IOD; Patient Treatment Preparation Procedure Parameter Description (300A,078E), Type 2 in Patient Treatment Preparation Procedure Sequence (300A,0790), and Patient Setup Photo Description (300A,0794), Type 2 in Referenced Patient Setup Photo Sequence (300A,078C), both sequences within Patient Treatment Preparation Sequence (300A,079F), at the top level of each CT, MR, and PET image IOD other than MR Spectroscopy and within Patient Setup Sequence (300A,0180) of the RT Plan, RT Beams Treatment Record, RT Ion Plan, RT Ion Beams Treatment Record, and RT Brachy Treatment Record IODs; Overlay Data, Type 1 in the Overlay Plane Module of the CT Image, MR Image, Positron Emission Tomography Image, and Nuclear Medicine Image IODs; Radiopharmaceutical Start DateTime (0018,1078), Type 1 in the Type 1 Radiopharmaceutical Information Sequence (0054,0016) of the Enhanced PET Image IOD; and Requested Procedure ID (0040,1001), Type 2 in Referenced Request Sequence (0040,A370), which is Type 1C at the top level of the SR Document General Module of every supported Structured Report IOD, required where the report was made for a request; and Source Manufacturer (300A,0216), Type 2 in Recorded Source Sequence (3008,0100), which is Type 1 at the top level of the RT Brachy Session Record Module of the RT Brachy Treatment Record IOD. Source Series Information Sequence and Referenced Patient Setup Photo Sequence are Type 3 wherever these IODs define them, and Patient Treatment Preparation Sequence is Type 3 at the top level of those image IODs and within Patient Setup Sequence, so Series Description and the two descriptions are removed with the sequence that holds them; Overlay Data and ROI Interpreter Sequence are removed as above; and an instance with Responsible Person or Responsible Organization is sequestered. So is every Enhanced PET Image instance that conforms to its IOD, under
basicandbasic-clean-descriptors, since no Type 3 sequence encloses Radiopharmaceutical Start DateTime there; Table E.1-1 gives it C under Retain Longitudinal Temporal Information with Modified Dates, which those presets do not select. Requested Procedure ID is emptied there, as above, so it sequesters no Structured Report, and Source Manufacturer is emptied there, as above, so it sequesters no brachy treatment record.A plain D on an attribute that the IOD does not define at that place acts as X there, and a plain Z there stays Z, following Note 13 after Table E.1-1a: Verifying Observer Sequence (0040,A073) “is only defined in structured report IODs and hence is described in Table E.1-1 as D since it is Type 1C; if encountered in an image instance, it should simply be removed (treated as X)”.
A plain Z on an attribute that is Type 1 or 1C at that place writes D’s dummy value, which Table E.1-1a’s definition of Z allows: “replace with a zero length value, or a non-zero length value that may be a dummy value and consistent with the VR”. In 2026d, no IOD of the first supported release has such a place.
Clinical Trial Protocol Ethics Committee Name (0012,0081) is removed, although Table E.1-1 gives it D, or K under Retain Institution Identity, which the maintainer decided on 10 October 2026. PS3.3 makes it Type 1C in the Clinical Trial Subject Module of each IOD of the first supported release: “Required if Clinical Trial Protocol Ethics Committee Approval Number (0012,0082) is present”. Table E.1-1 gives the approval number X under the Basic Profile and every option, so that condition never holds in the output, and PS3.5 Section 7.4.2 then does not allow the name, since its condition does not say that it may be present otherwise. With ROI Interpreter Sequence, it is one of the two attributes whose condition lapses in this way in every instance; each is removed alone, whatever its action. The conditions of the Common Instance Reference Module’s two sequences lapse only in an instance that de-identification leaves with no other reference to an instance, which depends on its content, so D-022 removes them only there.
Z and D write the values that D-021 sets.
Rationale. The strictest Type never removes an attribute that the IOD may require, so compound actions never make the output invalid, and it never retains more, because Z and D still replace the value. The cost is occasionally writing an empty or dummy value where removal was allowed. Evaluating conditions was rejected: PS3.3 writes them as free text, so an interpreter would be hand-built and error-prone, and it would gain almost no privacy. Removing every attribute that is not Type 1 was rejected because removing a Type 2 attribute makes the object invalid, which breaks import into planning systems. A plain X is applied differently: Table E.1-1a defines X as removal, so where the IOD requires the attribute, removing an optional sequence that encloses it keeps both the table’s action and the IOD’s integrity, and the rare instance where no such sequence exists is sequestered. Writing an empty or dummy value in place of a plain X was rejected because it is not the removal that the table specifies, so the exact Basic Profile claim would rest on reading E.1.1’s general permission to replace a value as overriding the table, which the standard does not state. Leaving such instances out of the conformance claim was rejected for the same reason: removal keeps the claim for every instance that it can keep valid. Removing the whole overlay group leaves a valid CT, MR, PET, or Nuclear Medicine image, since the Overlay Plane Module, and in a Nuclear Medicine image the Multi-frame Overlay Module, is optional in each, and removing ROI Interpreter Sequence leaves a valid RT Structure Set once ROI Creator Sequence is gone. Clinical Trial Protocol Ethics Committee Name is removed because D, or K, would make every instance that has it invalid once the approval number is gone, as
dciodvfyreports (D-030), and removing it discards only a dummy value, or a name that the Basic Profile does not keep; keeping D was rejected because no instance with the name could then conform to its IOD. The Common Instance Reference Module’s two sequences are removed only where their conditions can be seen to have lapsed from the data set’s structure: an instance whose remaining references all name instances of other studies keeps a Referenced Series Sequence whose condition does not hold, since telling which study a reference names needs the UIDs’ values, which the engine’s plan does not use, and D-022 accepts that trade-off. Instances keep the exact Basic Profile claim: removing the name keeps less than D does, E.1.1’s Note makes keeping the IOD intact the de-identifier’s responsibility, and Note 13 after Table E.1-1a already treats a D given to a Type 1C attribute as X where the attribute is not allowed. An attribute that the IOD does not define at that place needs no value, so D removes it, as Note 13 describes, and Z, which writes nothing identifying, is kept as the table gives it. A plain Z on a Type 1 attribute writes a dummy value because an empty value would make the output invalid. Table E.1-1a defines X/Z as “X unless Z is required to maintain IOD conformance (Type 3 versus Type 2)”, so it does not say what X/Z does at a Type 1 place; the Z it offers allows a dummy value, as a plain Z does, so X/Z there writes one too. Sequestering the instance instead was rejected, where the attribute’s VR has a dummy value (D-021), because it would discard an instance that the profile can de-identify.Tests. Each compound action gives the specified action for Types 1, 1C, 2, 2C, and 3; an attribute with different Types in different modules, including modules of conditional or user-optional usage, gets the action of its strictest Type; the Type depends on the enclosing sequence; an attribute that the IOD does not define at that place is removed, or emptied under Z/D; X/Z on a Type 1 or 1C attribute writes the dummy value, and does so in the generated IODs only for Referenced Study Sequence in the three sequences named above; and no Type 1 or Type 2 attribute with a compound action is removed. A plain X removes the attribute, and where the IOD requires it at that place, also the innermost enclosing sequence that is Type 3 at its own place, as for Series Description in Source Series Information Sequence and the two Patient Treatment Preparation descriptions, or sequesters the instance where there is none, as for Responsible Person and Responsible Organization, and for Radiopharmaceutical Start DateTime in Enhanced PET Image; removing Overlay Data removes its whole repeating group, and ROI Interpreter Sequence is removed; every plain action on Clinical Trial Protocol Ethics Committee Name removes it, and an instance that loses it with its approval number keeps every attribute its IOD requires; a plain D on an attribute that the IOD does not define at that place, such as Verifying Observer Sequence in a CT image, removes it, and a plain Z there empties it; a plain Z on a Type 1 or 1C attribute writes the dummy value; and a plain X empties Requested Procedure ID in the Referenced Request Sequence of every generated IOD that makes it Type 2 there, and only there, so that a dose report made for a request is released where its tree is kept, with the ID empty, and Source Manufacturer in Recorded Source Sequence of RT Brachy Treatment Record, the only generated IOD that makes it Type 2 there, and only there, while it is removed alone in RT Plan’s Source Sequence (300A,0210), so that the synthetic collection’s brachy treatment record is released under every policy with it empty, or kept under Retain Device Identity, and Source Serial Number empty beside it, and the conformance statement says so.
D-021: Dummy values#
Decision.
Z writes a zero-length value, except where a dummy value is already decided: the keyed pseudonyms for Patient ID and Patient’s Name (D-005), the synthetic birth dates of
tps-import(D-008), and D’s dummy value where a plain Z, or the Z that X/Z offers, applies to an attribute that is Type 1 or 1C at its place (D-020).D writes one conspicuous constant for each VR, valid for that VR:
DEIDENTIFIEDfor the text VRs (LO, SH, LT, ST, UC, and UT) and PN;19000101for DA;000000for TM;19000101000000for DT; zero for the numeric string VRs (DS and IS) and the binary number VRs (FL, FD, SL, SS, SV, UL, US, and UV); and the keyed replacement for UI (D-003). Where the constant equals the source value, a second constant is used, so the value always changes.The second constants are
DE-IDENTIFIED,19000102,000001,19000101000001, and one. A source value equals a constant when the two match as their VR defines them: text and PN ignoring case and padding, and a PN’s trailing^and=delimiters; DA, TM, and DT as the same date or time, ignoring a DT’s UTC offset and taking absent components at their least values; and the numeric VRs as the same number, so0.0equals zero. Equality is deliberately broad, since a value treated as equal still changes. Where any of an attribute’s source values equals the constant, the second is used. D writes the fewest values that the attribute’s VM allows, each the constant, and for UI the replacement of each source UID, even one that the pinned tables register, since D must replace the value.CS, SQ, and every other VR have no generic dummy value, nor has a UI attribute without a source UID to replace. A D on an attribute of such a VR needs a reviewed rule for that attribute; without one, the instance is sequestered rather than given an invalid value.
Person Identification Code Sequence (0040,1101), which Table E.1-1 gives D, has such a rule, which the maintainer decided on 1 October 2026. D writes one item, with Code Value (0008,0100)
DEIDENTIFIED, Coding Scheme Designator (0008,0102)99PYMEDPHYS, and Code Meaning (0008,0104)DEIDENTIFIED^DEIDENTIFIED. Where a source item’s Code Value or Code Meaning equals its constant, compared as above, the item takes the second constants,DE-IDENTIFIEDandDE-IDENTIFIED^DE-IDENTIFIED, with the same designator. In the first supported release’s IODs, Table E.1-1 removes no sequence that encloses it in four places: Asserter Identification Sequence (0044,0103) in RT Assertions Sequence (0044,0110) of the RT Plan and RT Ion Plan IODs, where it is Type 2C, and Interlock Resolution User Sequence (300A,0746) in Interlock Sequence (300A,0740) of Treatment Session Beam Sequence (3008,0020) of the RT Beams Treatment Record IOD and of Treatment Session Ion Beam Sequence (3008,0021) of the RT Ion Beams Treatment Record IOD, where it is Type 1. RT Brachy Treatment Record, which has no interlock, adds no place: its Person Identification Macro is in Operator Identification Sequence (0008,1072), which Table E.1-1 gives X/D, within the Override Sequence (3008,0060) of its delivered control points, where the sequence is Type 3 and so removed with its items.In 2026d, two other attributes of the first supported release’s IODs resolve to D on a VR without a generic dummy value. Referenced Performed Procedure Step Sequence (0008,1111), which Table E.1-1 gives X/Z/D, is Type 1C in the series module of each of the eight multi-frame IODs, “Required if a Performed Procedure Step SOP Class was involved in the creation of this Series”: the CT Series Module (PS3.3 Section C.8.15.1) of Enhanced CT Image and Legacy Converted Enhanced CT Image, the MR Series Module (Section C.8.13.6) of Enhanced MR Image, Enhanced MR Color Image, Legacy Converted Enhanced MR Image, and MR Spectroscopy, and the Enhanced PET Series Module (Section C.8.22.1) of Enhanced PET Image and Legacy Converted Enhanced PET Image. ICC Profile (0028,2000), which D-022 gives X/Z/D, is Type 1 in the ICC Profile Module of the Enhanced CT Image, Enhanced MR Image, Enhanced MR Color Image, Segmentation, and Nuclear Medicine Image IODs, which is mandatory in Enhanced MR Color Image, user-optional in Enhanced CT Image, Enhanced MR Image, and Nuclear Medicine Image, and required in Segmentation where Photometric Interpretation is
PALETTE COLOR, as a label map’s can be, and of the Color, Pseudo-Color, and Blending Softcopy Presentation State IODs, in which it is mandatory, and the Variable Modality LUT Softcopy Presentation State IOD, which requires it where the Palette Color Lookup Table Module is present. Each has a reviewed rule, which the maintainer chose on 7 October 2026, and so has a third, below, which the maintainer chose on 1 November 2026; the two sequences of the Structured Reports follow it:In Referenced Performed Procedure Step Sequence, D writes one item for each source item, with Referenced SOP Class UID (0008,1150)
1.2.840.10008.3.1.2.3.3, the Modality Performed Procedure Step SOP Class, and Referenced SOP Instance UID (0008,1155) the keyed replacement of the source item’s (D-003). Where the sequence has no item, or an item has no Referenced SOP Instance UID, there is nothing to replace, and the instance is sequestered.In place of an RGB ICC Profile, D writes the source profile cleaned of everything but its colorimetry, as the maintainer chose on 31 October 2026 in place of the fixed profile that he chose on 7 October 2026, which D still writes where the source cannot be cleaned. PS3.3 Section C.11.15.1.1 requires ICC Profile to be an input device profile whose input colour space is RGB, whatever the image’s Photometric Interpretation, so only an RGB profile is replaced, and where the source is not an ICC profile, or is one of another colour space, such as a grey profile, which does not conform there, the instance is sequestered. The cleaner reads the profile as ICC.1:2001-04 (version 2) and ICC.1:2010 and ICC.1:2022 (version 4) define it:
It keeps the colorimetric tags that the source’s version defines, each of a type that the version defines for it: the matrix and tone curve tags, the media white point, luminance, and the lookup tables of each rendering intent in each direction (8-bit and 16-bit in version 2; those and the A-to-B and B-to-A types in version 4), and chromatic adaptation, with, in version 2, the media black point, and, in version 4, parametric curves, the floating-point
D2BxandB2Dxtransforms, and coding-independent code points; and the tags that describe the colorimetry, which are chromaticity, measurement, and viewing conditions, and, in version 4, the colorimetric intent image state and the perceptual and saturation rendering intent gamuts, each signature one that ICC.1 registers. It parses each kept tag against its type’s structure and writes it again from the values parsed, so no reserved field, padding, unreferenced byte, or byte after a structure survives.It removes every other tag: every text tag, such as the description, copyright, device manufacturer and model descriptions, viewing conditions description, characterisation target, screening description, and profile sequence description; every private tag; the technology signature, calibration date, and output and proofing tags; and each tag of another version.
Its header keeps the source’s version, profile connection space (PCS), rendering intent, PCS illuminant, and the two profile flags that ICC.1 defines, which say whether the profile is embedded and whether it may be used apart from the image. It names no preferred CMM, platform, device manufacturer, model, attributes, or creator, gives 1 January 1900 as its date, as D’s dummy dates do, and has zero in its reserved bytes; it is an input device profile, so a display or colour space source, which ICC.1 lets map RGB to the PCS in the same way, conforms to Section C.11.15.1.1 once written. A colour management module reads a version 2 display profile’s media white point by its class, and with it the chromatic adaptation that it derives where the profile has no
chadtag: LittleCMS takes D50 as such a profile’s media white point and adapts from the stored white point to D50, but takes an input profile’s stored white point as it is, which changes absolute colorimetric rendering where the stored white point is not D50. A version 2 display profile is therefore cleaned only where its media white point is D50, within one unit of the last place of each s15Fixed16Number, where both classes give the same white point and adaptation. A version 4 profile’s profile ID is the MD5 digest of the written profile that ICC.1 defines; a version 2 profile has zero there. Its description and copyright areDEIDENTIFIED, orDE-IDENTIFIEDwhere the source has the same bytes as the profile that the first would give, each of the type its version defines (textDescriptionTypeandtextTypein version 2,multiLocalizedUnicodeTypein version 4).The source cannot be cleaned where it is not of version 2 or 4, is not an input device, display device, or colour space profile, has a PCS other than CIEXYZ or CIELAB, a PCS illuminant more than 0.001 from D50 in any component, or an undefined rendering intent, has a header, tag table, or tag whose bounds do not parse, holds a tag twice, holds a colorimetric tag that a colour management module reads to convert colours of a type that its version does not define for it, or whose data do not parse, for example a processing element that ICC.1 reserves for colour appearance spaces, lacks the media white point or a complete transform from RGB to the PCS, which is an A-to-B table for the perceptual intent or, with a CIEXYZ PCS, the three colorants and tone curves, or is a version 2 display profile whose media white point is not D50, as above. A descriptive tag whose data do not parse is removed instead, since no transform reads it. There D writes a fixed ICC version 2.4 input profile (ICC.1:2001-04) of the sRGB colour space of IEC 61966-2.1, a matrix and tone curve profile, of which nothing comes from the source; its description is
DEIDENTIFIED sRGB, and its copyright isNo copyright, use freely; its header names no device, platform, or creator, and gives 1 January 1900 as its date, and its media white point is D50. The fixed profile can itself be cleaned, so it never has a source’s bytes.The release report counts the profiles of each kind that the run released or held, and the fixed profiles by the reason the source could not be cleaned, as
structure,version,device-class,connection-space,header,tag-type,tag-data,no-white-point,no-transform, ordisplay-white-point; the conformance statement describes both profiles.Color Space (0028,2002), which names the colour space of the profile, is removed under every option (D-022), so it cannot contradict the profile written. Pixel values are preserved. Where the cleaned profile is written, colour rendering is preserved too: a colour management module maps every device value as it does with the source. Where the fixed profile is written, colour rendering is not: replacing the source profile’s colorants and tone curves can substantially change colour and brightness in a colour-managed viewer. For example, a source profile with sRGB primaries and a linear tone curve shows a stored neutral value of 128 as about 188 on an sRGB display, and the fixed profile shows it as 128.
Institution Code Sequence (0008,0082), which Table E.1-1 gives X/Z/D, is Type 1C in Interlock Resolution User Sequence of the RT Beams Treatment Record and RT Ion Beams Treatment Record IODs, above, whose Person Identification Macro (PS3.3 Table 10-1) requires it where Institution Name (0008,0080) is not present. No enclosing sequence is removed, so it resolves to D. It has a reviewed rule there, which the maintainer chose on 1 November 2026, in place of sequestering the instance: D writes one item, with Code Value
DEIDENTIFIED, Coding Scheme Designator99PYMEDPHYS, and Code MeaningDEIDENTIFIED, as plain text. Where a source item’s Code Value equalsDEIDENTIFIEDas SH text, or its Code Meaning equals it as LO text, compared as above, the item takes the second constant,DE-IDENTIFIED, for both, with the same designator. The rule holds only for the sequence directly in an item of Interlock Resolution User Sequence (300A,0746), in Interlock Sequence (300A,0740) of Treatment Session Beam Sequence (3008,0020) of the RT Beams Treatment Record IOD and of Treatment Session Ion Beam Sequence (3008,0021) of the RT Ion Beams Treatment Record IOD, the only places of the first supported release’s IODs where it resolves to D outside a removed sequence; elsewhere it has no reviewed rule, so a D on it there still sequesters the instance. In Operator Identification Sequence (0008,1072) of Override Sequence (3008,0060), Table E.1-1 gives that sequence X/D, and it is Type 3 there, so it is removed with any Institution Code Sequence in it. Institution Name in the interlock resolution user is also Type 1C and takes D’s text constant. The conformance statement lists each place where D has no dummy value as one where the instance is sequestered, as it lists a required UR value’s, such as Pixel Data Provider URL (0028,7FE0) where Pixel Data is provided by reference (D-022).Content Sequence (0040,A730), which Table E.1-1 gives D, is required at the top level of every supported Structured Report IOD where the root has content items, as every report’s does. It has no reviewed rule, so a report is sequestered under the Basic Profile, unless Clean Structured Content keeps its tree (D-047).
Verifying Observer Sequence (0040,A073), which Table E.1-1 gives D under every option, is Type 1C in the SR Document General Module of every Structured Report IOD, required where Verification Flag (0040,A493) is VERIFIED. It has a reviewed rule, which the maintainer chose on 25 October 2026: D keeps each source item, with only the four attributes that PS3.3 Table C.17-2 defines in it, each under its own row of Table E.1-1, and removes every other attribute of the item, with everything in it. Verifying Observer Name (0040,A075) and Verifying Organization (0040,A027) are D, so each takes the text constant, or the second where its source value equals the first; Verifying Observer Identification Code Sequence (0040,A088) is Z, and Type 2 there, so it is written with no items; and Verification DateTime (0040,A030) is D, K under Full Dates, and C under Modified Dates, so it takes the DT constant, is kept, or is modified as the instance’s other dates are (D-007). An attribute that a source item lacks is not added, since no gap is filled with a made-up value (D-031), as the maintainer confirmed on 25 October 2026. Every supported Structured Report IOD defines it, so a verified report is planned as an unverified one is; elsewhere a plain D on it gives X (D-020).
Amendment, 30 October 2026. A Procedure Log’s entries, the items of its content tree that are targets of CONTAINS from its root, are “strictly ordered by monotonically increasing Observation DateTime (0040,A032) Values” (PS3.3 Section A.35.7.3.1.2). Table E.1-1 gives Observation DateTime X/D, which resolves to D in that Type 1 place unless Full Dates keeps it or Modified Dates shifts it, and one constant would give every entry the same value and write the log out of order. The maintainer decided on 30 October 2026 that each entry’s Observation DateTime instead takes the dummy datetime of its rank among the entries’ distinct source values:
19000101000000, the DT constant, for the earliest, and one second more for each later one, so entries with equal source values share a dummy. As with the second constant, where any of these dummies would equal any entry’s source value, compared as above, the whole series moves on by its own length until none does, so no source value is written, as a second run over a written log would otherwise do. A log whose entries’ source values are not in increasing order, are not DT values, or have different UTC offsets is not kept, and so is sequestered (D-047). The dummies show only the order of the entries, which the IOD requires and the order of the items already shows, and which neighbouring entries share a time; they keep no date, time, or interval. Every other DT that D writes, including an Observation DateTime deeper in the tree or on a first-level item of another relationship, such as observation context (PS3.3 Table C.17-6), takes the constant and plays no part in the order.Dummy values never name PyMedPhys; the markers do (D-012). The one exception is the Coding Scheme Designator
99PYMEDPHYSof the two coded items above, which the maintainer chose on 1 October 2026 for Person Identification Code Sequence and on 1 November 2026 for Institution Code Sequence: it names who defines the code, not the person or the institution, and each item’s Code Value and Code Meaning are the constants. The conformance statement describes each dummy value, as E.1.3 requires.
Rationale. Constants are obviously synthetic, reveal nothing, are deterministic, and are always valid for their VR, and a zero-length value carries the least information and is always valid for Type 2. Plausible random values were rejected because they can be mistaken for real data, may match real values, and are not reproducible. Keyed values derived from the source were rejected because equal source values would give equal dummy values, which leaks equality and links records. Dummy values never name PyMedPhys because they sit in clinical fields, where they read as data:
DEIDENTIFIEDmeans the same to any reader, and the markers are where the de-identifier describes itself. The Coding Scheme Designator of the dummy code is a narrow exception, because a private coding scheme’s designator conventionally identifies who defines its codes. PS3.16 Chapter 8 requires a local or private coding scheme to be identified by an alphanumeric designator beginning with “99”, as HL7 V2 Table 0396 specifies, and PS3.3 Section 8.2 notes that HL7 V2 defines such designators as private or local; the rest of a private designator conventionally names the scheme’s owner.99PYMEDPHYS, 11 of the 16 characters that SH allows, therefore says which organisation defined the code. It is metadata about the code, not content that reads as data about the person, and the Code Value and Code Meaning stay the conspicuous constants. The item follows PS3.3 Table 10-1, the Person Identification Macro, which requires “One or more Items” in the sequence and lets Code Meaning follow the rules of PN, “except that a single component (i.e., the whole name unseparated by caret delimiters) is not permitted”, so the constant has two components. The same macro gives that PN rule to Person Identification Code Sequence alone; for Institution Code Sequence it says only “Only a single Item shall be included in this Sequence”, so its item’s Code Meaning is the plain LO constant of PS3.3 Section 8.3, and it has one item. Writing the item, rather than sequestering the record, releases a treatment record whose interlock was resolved by a person identified by an institution code, as the person code’s item already does, and writes nothing from the source. Removing the sequence was rejected because the engine resolves an attribute’s action from its Type without evaluating its condition, so a Type 1C attribute counts as required wherever it is present (compound_actions), and here the condition can hold: Table 10-1 requires the sequence where Institution Name is not present, and an item that names the institution only by its code has no Institution Name, which D does not add (D-031), so removing the sequence from it would leave neither, and the item would not conform. Giving the rule to Institution Code Sequence everywhere was rejected because the maintainer reviewed it only at this place: a future IOD that requires the sequence elsewhere still sequesters until its place is reviewed. At the place above, in Asserter Identification Sequence, the Assertion Macro (PS3.3 Table 10.30-1) defines the sequence instead through Table C.17-3b, the Identified Person or Device Macro, as Type 2C with “Zero or one Item shall be included in this Sequence”; the one item satisfies both macros. The procedure step’s items take the keyed replacement rather than a constant, the deliberate exception to rejecting keyed values that applies to every UID, as for U, because Referenced SOP Instance UID is a reference, which Table E.1-1 replaces (U) wherever else it occurs, so the replacement is the same as any other reference to that step would get, and no constant UID is shared between unrelated series; the UID is the only value read, and the class is fixed to the Modality Performed Procedure Step SOP Class, which a modality creates for the series it acquires, so nothing else of the source item is written. An ICC profile is a file in another format whose text, such as its description, copyright, and device and creator fields, can name a site, a department, or a calibration, so the cleaned profile keeps none of it, and keeps only what a colour management module reads to convert colours and the numbers that describe them, so that colour-managed viewers show the released images as they showed the source. Each kept tag is written again from what was parsed, rather than copied, so that only structures that the specification defines are written and no unreferenced byte carries text through. Keeping colorants and curves, which the 7 October 2026 choice rejected because they could identify a device, was chosen on 31 October 2026 for colour fidelity: in the IODs that require the profile, colour is a rendering made by the modality’s or workstation’s software, so its profile characterises a product or rendering pipeline, as Manufacturer’s Model Name (0008,1090) does, which the engine keeps, rather than one device, as Device Serial Number (0018,1000) does, which Table E.1-1 removes (inference); a profile measured for one device is accepted as a residual risk of the same kind. The cleaned profile is written under every option, not only under Retain Device Identity, as was also chosen on 31 October 2026. A profile that cannot be cleaned is not sequestered: the fixed profile keeps the instance valid, since ICC Profile is Type 1 where D applies, and sRGB, a standard RGB colour space in wide use, keeps the colours plausible, so such instances are released with the colour fidelity of the 7 October 2026 choice rather than set aside. The two written profiles differ in their descriptions, so a reader can tell which an instance holds. A grey source profile does not conform to PS3.3 Section C.11.15.1.1, and a grey replacement would not either, so it is sequestered rather than given a profile that would be invalid there, as are other colour spaces. Verifying Observer Sequence keeps each source item, rather than taking one fixed item, so that each Verification DateTime takes its own row’s action, which Full Dates and Modified Dates change, as a fixed item could not; the number of verifiers is kept, which names no one. Each attribute takes its own row rather than a constant chosen for the item, so the item follows the policy wherever Table E.1-1 does, and the item keeps only the four attributes, since PS3.3 defines nothing else there and a reviewed rule should write only what has been reviewed.Tests. Z writes a zero-length value except for the decided pseudonyms and synthetic birth dates, and D’s dummy value where the attribute is Type 1 or 1C; D writes its VR’s constant, or the second constant where the source value equals the first in any form, such as padded, in another case, or
0.0for DS; every dummy value is valid for its VR and its attribute’s VM; different source values give the same dummy value; a D on an attribute of another VR without a reviewed rule sequesters the instance; D on Person Identification Code Sequence writes one item with the constants above, or with the second constants where a source item’s Code Value or Code Meaning equals the first, each valid for its VR, and the written file holds that item; D on Referenced Performed Procedure Step Sequence writes one item for each source item, with the keyed replacement of its UID, and sequesters the instance where there is no UID to replace; D on Institution Code Sequence in the item of an interlock’s resolution user, in an RT Beams Treatment Record and in an RT Ion Beams Treatment Record, writes one item with the constants above, or the second constant where a source item’s Code Value or Code Meaning equals the first, each valid for its VR, releases the record, and is listed in the conformance statement as D there, while D writes that item’s Person Identification Code Sequence item and Institution Name’s constant; D on Institution Code Sequence anywhere else has no reviewed rule and sequesters the instance, and the conformance statement lists each place where D has no dummy value as sequestering; D on ICC Profile writes the source cleaned of everything but its colorimetry, which LittleCMS maps, at every rendering intent and in both directions, to the same colours as the source for every colour of a grid, for version 2 and version 4 profiles of every transform form that the cleaner keeps, including a version 2 input profile with a chromatic adaptation tag and a D65 media white point, written from the ICC specifications independently of the cleaner, for LittleCMS’s own sRGB profile, and for the profile among pydicom’s test files, with no text tag, private tag, header identity field, reserved byte, or padding of the source left, a version 4 profile’s ID recomputed, the second description where the source has the same bytes, and the descriptive tags that do not parse removed; writes the fixed sRGB profile, which LittleCMS reads, whose colorants sum to its white point, and whose tone curve is that of sRGB, for each kind of source that cannot be cleaned, including a version 2 display profile with a D65 media white point, whose absolute colorimetric rendering LittleCMS changes when only its class is changed; counts in the release report, for the instances released or held, each copy once, the cleaned profiles and the fixed ones by reason; and sequesters the instance for any other colour space; and, in synthetic VERIFIED Comprehensive SRs, D on Verifying Observer Sequence keeps every Structured Report IOD’s four item attributes and no others, plans each under its own row, removes any other attribute of an item with its contents, writes one item for each source item, with the text constants, the second where a source name equals the first, the DT constant, and an empty code sequence, keeps Verification DateTime under Full Dates and modifies it under Modified Dates, and is described in the conformance statement with the action that the policy gives each attribute. A Procedure Log’s entries take the dummy datetimes of their ranks, one second apart, entries with equal source values sharing one, and a series that would write a source value moves on by its length; nothing else is given one.
D-022: Text and other attributes that Table E.1-1 omits#
Decision.
A reviewed L2 list gives an action, attribute by attribute, to each text attribute (VR LO, SH, LT, ST, UC, or UT) that Table E.1-1 omits and a supported IOD uses. In 2026d, the first supported release’s 61 IODs use 196. They range from coded vocabulary, such as Code Value, Coding Scheme Designator, and Code Meaning; through equipment descriptions, such as Manufacturer, Software Versions, and Convolution Kernel; to operator-typed RT text, such as Beam Name, Block Name, Patient Setup Label, Dose Comment, Setup Image Comment, and Text Value (0040,A160); accessory identifiers, such as Wedge ID, Block Tray ID, Applicator ID, Compensator ID, and General Accessory ID; and accessory codes that a device reads, such as Accessory Code.
The list puts each attribute in one of three groups, apart from the stricter rules below:
operator-typed labels and text: X/Z/D, resolved by Type (D-020), and C under Clean Descriptors (D-009). In 2026d, there are 92.
accessory and equipment identifiers, treated as device identity: X/Z/D, and K under Retain Device Identity. In 2026d, there are 33.
coded and technical values: K. In 2026d, there are 50: codes and the vocabulary that qualifies them, Code Value, Long Code Value, Coding Scheme Designator, Coding Scheme Version, Coding Scheme Registry, Coding Scheme External ID, and Code Meaning; values that the standard constrains, Strain Nomenclature, Genetic Modifications Nomenclature, Rescale Type, Overlay Subtype, Fraction Pattern, and Device Alternate Identifier Format; values that equipment or software writes, Manufacturer, Manufacturer’s Model Name, Manufacturer’s Model Version, Software Versions, Algorithm Version, Convolution Kernel, Filter Type, Fluence Mode ID, and Source Isotope Name; and the identifiers of private data elements that software writes, Private Creator Reference, Private Data Element Name, Private Data Element Keyword, Selector Sequence Pointer Private Creator, and Selector Attribute Private Creator; and ten that only the CT, MR, and PET IODs use, below; Modality LUT Type, which RT Image uses, below; four that only RT Ion Plan and RT Ion Beams Treatment Record use, below; Conceptual Volume Combination Expression, which only Enhanced RT Image and Enhanced Continuous RT Image use, below; Intended Start Day of Week, which only the second-generation RT IODs use, below; the two font names of a Presentation State’s text, below; and four that only Encapsulated PDF uses, below. Free text that a person types, such as a comment, label, or description, is never in this group.
Names and identifiers of people, organisations, records, and networks, and identifiers that a device reads, have a rule stricter than that of operator-typed text: X/Z/D, resolved by Type, under every option, with no action under Clean Descriptors or Retain Device Identity. It is chosen because these values name people, organisations, records, or networks, or, read by a device such as a bar-code reader, identify accessories often made for one patient, rather than describe content as descriptors do. In 2026d, there are 16: Coding Scheme Responsible Organization (0008,0116), Mapping Resource Name (0008,0122), Strain Stock Number (0010,0214), Strain Source (0010,0217), Breed Registration Number (0010,2295), NTP Source Address (0018,1803), Algorithm Source (0024,0202), Local Namespace Entity ID (0040,0031), Universal Entity ID (0040,0032), HL7 Instance Identifier (0040,E001), Image ID (0054,0400), Tracking ID (0062,0020), Storage Media File-set ID (0088,0130), and the accessory identifiers that a device reads, Accessory Code (300A,00F9), Patient Support Accessory Code (300A,0354), and Tray Accessory Code (300A,0355).
The text of overlays, Overlay Description (60xx,0022) and Overlay Label (60xx,1500), has the same stricter rule, because Table E.1-1 cleans overlay text only under Clean Graphics, under which the engine removes it until a cleaner of overlays exists (D-041). With the two alternative calendar dates and De-identification Method, below, the three groups (92, 33, and 50) and these 18 make the 196.
Every rule carries a note giving the reason for its action.
Of the 196, 31 are used only by the ten CT, MR, and PET IODs that the maintainer added to the first supported release on 7 October 2026 (D-010), and not by CT Image or the RT IODs. These IODs are Enhanced CT Image, Legacy Converted Enhanced CT Image, MR Image, Enhanced MR Image, Enhanced MR Color Image, Legacy Converted Enhanced MR Image, MR Spectroscopy, Positron Emission Tomography Image, Enhanced PET Image, and Legacy Converted Enhanced PET Image. Sixteen are operator-typed labels and text, among them Sequence Name, which PS3.3 calls user-defined, the free-text names of radiopharmaceuticals and intervention drugs and their routes, whose code sequences carry them as codes, the arterial spin labelling descriptions, Dimension Description Label, and the PET correction and reconstruction methods, which the scanner usually writes but PS3.3 defines as free text. Five are device identity: the names of the receive and transmit coils, which a site can choose for its own coils, the coils’ manufacturers, which can be a site that builds its own, and the names of a multi-element coil’s elements, which a site can choose in the same way. Ten are coded and technical values: Imaged Nucleus, Cardiac Framing Type, Collimator/Grid Name, Pulse Sequence Name, which PS3.3 says may be specific to the vendor, unlike the user-defined Sequence Name, Applicable Safety Standard Description, which names a published standard, Image Filter, written like Convolution Kernel, Stack ID and Frame Label, which name groups of frames, which Dimension Index Pointer can name, and of which Stack ID is required in Enhanced PET, so that changing them would break how frames are organised, and the private creators that Dimension Index Private Creator and Functional Group Private Creator name. Keeping Pulse Sequence Name, Stack ID, and Frame Label accepts the residual risk that a site writes a name in them, since PS3.3 does not say who writes them.
The list also gives a rule, ahead of supporting them, to the 16 text attributes that Table E.1-1 omits and that, of the IODs that the first supported release supported when they were reviewed or that the target coverage (Scope) names, only five use: RT Beams Treatment Record, RT Image, Spatial Registration, Deformable Spatial Registration, and Segmentation. The maintainer decided on 25 October 2026 to support these IODs (D-010), and the first supported release now supports all five: Spatial Registration and Deformable Spatial Registration, which use two of the 16, Content Description and Frame of Reference Transformation Comment, RT Beams Treatment Record, which uses five, its five descriptions below, RT Image, which uses its label, name, description, machine name, and Modality LUT Type, and Segmentation, which uses Segment Label, Segment Description, Segment Algorithm Name, Content Description, and Tracking ID. Thirteen are operator-typed labels and text: Segment Label, Segment Description, and Segment Algorithm Name, which PS3.3 says may be identical to Algorithm Name and which is treated as Algorithm Name is; Content Description, which PS3.3 calls descriptive identifying text for human readers; RT Image Label, RT Image Name, and RT Image Description, treated as Table E.1-1 treats RT Plan Label, RT Plan Name, and RT Plan Description; Frame of Reference Transformation Comment; and, in the treatment record, Measured Dose Description, Calculated Dose Reference Description, Override Reason, Treatment Status Comment, and Treatment Termination Description. Radiation Machine Name is device identity, as Table E.1-1 treats Treatment Machine Name. Modality LUT Type is kept, as Rescale Type is, since the two share their Defined Terms (PS3.3 Section C.11.1.1.2). Tracking ID (0062,0020), a label that tracks a finding across reporting objects and that PS3.3 requires to be unique within its domain, identifies a record about the patient, so it has the stricter rule for names and identifiers above; Table E.1-1 replaces Tracking UID (0062,0021), which accompanies it. Every UID and every date, time, and datetime that these IODs use already has a role (D-003, D-007). Those that none of the IODs supported before them uses are all listed in Table E.1-1: five UIDs that it replaces, Pyramid UID, Palette Color Lookup Table UID, Tracking UID, Source Frame of Reference UID, and Fiducial UID, each the UID of an instance; and eight dates, times, and datetimes of treatment, each a subject event. A rule applies by tag wherever its attribute appears, so in an instance of a supported IOD that holds one of the 16 where its IOD does not define it, the rule replaces removal by Type, the action for text that no rule covers. The two differ only for Modality LUT Type, which is kept, and under Clean Descriptors and Retain Device Identity, which clean the 13 operator-typed attributes and keep Radiation Machine Name.
The list also gives a rule, ahead of supporting them, to the two text attributes that Table E.1-1 omits and that, of the 20 IODs that the first supported release supported when they were reviewed, Segmentation and the four Radiation Dose SR IODs, only the last four use: X-Ray, Enhanced X-Ray, Radiopharmaceutical, and Patient Radiation Dose SR, which the maintainer added to the planned coverage on 25 October 2026. Both are operator-typed text: Completion Flag Description (0040,A492), an explanation of Completion Flag that PS3.3 does not constrain further, and Selector UC Value (0072,006F), the text of the cells of a TABLE content item, which the Enhanced X-Ray Radiation Dose SR allows, treated as Table E.1-1 treats Selector LO, LT, SH, ST, and UT Value. Table E.1-1 lists the other three text attributes that only these IODs use, all in SR Document General: Placer Order Number / Imaging Service Request, Filler Order Number / Imaging Service Request, and Verifying Organization. Every UID and every date, time, and datetime that these IODs use already has a role (D-003, D-007). Those that neither the supported IODs nor the target IODs use are all listed in Table E.1-1: Observation UID, the UID of an instance; Verification DateTime, Participation DateTime, and Referenced DateTime, each a subject event; and Selector DT Value, which is also the DateTime of a TABLE content item’s cells. Its role stays other, so that Modified Dates gives it a fixed dummy value rather than the subject’s offset, because only the concepts of a cell’s row and column, which PS3.3 lets a table leave out, say what the value records. The rules apply by tag wherever their attributes appear; elsewhere they differ from removal by Type, the action for text that no rule covers, only under Clean Descriptors, which cleans them. How Clean Structured Content cleans these IODs’ content items is decided by concept (D-047), and supporting each of them, as with every other Structured Report IOD of the target coverage (Scope), is a change of its own (D-010); the first supported release now supports all four, the Basic Text, Enhanced, Comprehensive, Comprehensive 3D, and Extensible SRs, and the Key Object Selection Document, Mammography CAD SR, Chest CAD SR, Colon CAD SR, Procedure Log, Spectacle Prescription Report, Macular Grid Thickness and Volume Report, and Waveform Annotation SR, which use no attribute that the IODs reviewed here do not, nor do the Structured Report IODs that it does not yet support. Verifying Observer Sequence (0040,A073), which Table E.1-1 gives D under every option, is Type 1C at the top level of the SR Document General Module, required where Verification Flag (0040,A493) is VERIFIED, and a sequence has no generic dummy value; D-021 gives it a reviewed rule, which keeps each verifier’s item with dummy values, so a verified report is not sequestered for it.
The list also gives a rule, ahead of supporting them, to the 13 text attributes that Table E.1-1 omits and that, of the IODs that the first supported release supports or that were reviewed before them, only RT Ion Plan and RT Ion Beams Treatment Record use, which the maintainer added to the target coverage on 31 October 2026 (D-010). They describe an ion beam’s accessories and how it is delivered, in the RT Ion Beams Module, the RT Ion Beams Session Record Module, and the Patient Support Identification Macro (PS3.3 Sections C.8.8.25, C.8.8.26, and C.8.8.28). Three are operator-typed text: Range Shifter Description, Lateral Spreading Device Description, and Range Modulator Description, user-defined descriptions of accessories, treated as Table E.1-1 treats Compensator Description and Bolus Description. Five are device identity: Snout ID, Range Shifter ID, Lateral Spreading Device ID, and Range Modulator ID, user or machine supplied identifiers of accessories of one treatment machine, treated as Wedge ID and Block Tray ID are, and Patient Support ID, which identifies one manufacturer-specific patient support device, as Table E.1-1 treats Treatment Machine Name. Four are technical values, which are kept: Range Shifter Setting and Lateral Spreading Device Setting, which give the presence, thickness, or characteristics of those devices at each control point in an encoding that PS3.3 Section C.8.8.25.5 makes machine specific; Scan Spot Tune ID, which identifies the machine’s configuration that produces a scanned beam’s spots, such as the nominal spot size; and Beam Current Modulation ID, which identifies the beam current modulation pattern that a modulator wheel is delivered with. Each is Type 1 or 1C where these IODs define it and is needed to reproduce the beam, and each names a setting or configuration of the machine rather than a device or a person, so each is kept, as Fluence Mode ID is; keeping Scan Spot Tune ID and Beam Current Modulation ID accepts the residual risk that a site writes a name in them, since PS3.3 lets a user supply them. Patient Support Accessory Code (300A,0354), which PS3.3 describes as an identifier to be read by a device such as a bar code reader, has the stricter rule for names and identifiers above, as Accessory Code and Tray Accessory Code do. Table E.1-1 lists none of the 122 attributes that only these IODs use; the other 109 are codes, numbers, and sequences of the beams, their accessories, and their delivery, which the rule for attributes that no rule covers keeps where these IODs define them, with a kept sequence’s items handled by their own rules. The IODs reviewed before them use every UID, date, time, datetime, person name, and URL that these IODs use, so each already has its role or its rule (D-003, D-007). A rule applies by tag wherever its attribute appears, so in an instance of a supported IOD that holds one of the 13 where its IOD does not define it, the rule replaces removal by Type, the action for text that no rule covers; the two differ only for the four technical values, which are kept, and under Clean Descriptors and Retain Device Identity, which clean the three descriptions and keep the five identifiers. The two IODs are supported (D-010), so the 13 are among the 196.
RT Brachy Treatment Record and RT Treatment Summary Record, which the maintainer added to the target coverage on 31 October 2026 (D-010), were reviewed ahead of supporting them in the same way, need no rule of their own, and are supported (D-010). Every module of RT Treatment Summary Record is a module of RT Beams Treatment Record (PS3.3 Tables A.29.3-1 and A.31.3-1), and RT Brachy Treatment Record adds to them only the RT Brachy Session Record Module (Section C.8.8.22, Table C.8-58), whose text attributes, such as Application Setup Name, Source Applicator ID, Channel Shield Name, Source Isotope Name, Override Reason, and Treatment Termination Description, are those of RT Plan’s RT Brachy Application Setups Module or of RT Beams Treatment Record’s RT Beams Session Record Module. So neither uses a text attribute, UID, person name, or URL that the IODs supported or reviewed before them do not use, and each already has its role or its rule (D-003, D-007). Removal by Type gives each attribute that they use and that Table E.1-1 or a rule gives a compound action an action that it already takes in an IOD reviewed before them, with one exception: Source Serial Number (3008,0105), which Table E.1-1 gives X/Z, and K under Retain Device Identity, is Type 2 in Recorded Source Sequence (3008,0100), so it is emptied there, while RT Plan defines it as Type 3 in Source Sequence (300A,0210), where it is removed. Source Applicator ID is Type 2 in Recorded Source Applicator Sequence (3008,0140), so it is emptied there, as its note says. A plain X is different, since it removes the attribute whatever its Type (D-020): Source Manufacturer (300A,0216), which Table E.1-1 gives X, is Type 2 in the Type 1 Recorded Source Sequence, so its removal would leave every conforming RT Brachy Treatment Record invalid, and such an instance would be sequestered unless Retain Device Identity keeps it, so under
basic,basic-clean-descriptors, andpublic-release, while RT Plan defines it as Type 3 in Source Sequence, where it is removed alone; it is emptied there instead (D-020). Every other place in these IODs where a plain X falls on a required attribute, Responsible Person and Responsible Organization in the Patient Module and the Patient Treatment Preparation descriptions in Patient Setup Sequence, is one that the IODs reviewed before them have, with the same removal, and neither IOD has a place, outside a sequence that the Basic Profile removes, where a plain Z falls on a Type 1 attribute or a D on a sequence or a URL. The only dates and times that RT Brachy Treatment Record adds are Safe Position Exit Date (3008,0162), Safe Position Exit Time (3008,0164), Safe Position Return Date (3008,0166), and Safe Position Return Time (3008,0168), which record when a source left its safe position and returned to it; Table E.1-1 lists them with D, K under Full Dates, and C under Modified Dates, and their role is a subject event (D-007). Its 21 other new attributes are codes, numbers, and sequences of the recorded channels, sources, applicators, shields, accessories, and control points delivered, and of the pulses of a pulsed delivery, none listed in Table E.1-1 or given a rule, which the rule for attributes that no rule covers keeps where it defines them, with a kept sequence’s items handled by their own rules. RT Treatment Summary Record uses no attribute that the IODs reviewed before them do not use.Nuclear Medicine Image, which the maintainer added to the target coverage on 31 October 2026 (D-010), was reviewed in the same way ahead of supporting it. Of the IODs that the first supported release supports, only it uses three text attributes that Table E.1-1 omits. Two are operator-typed text: Processing Function (0018,5020), in the NM Image Module (PS3.3 Section C.8.4.9, Table C.8-9), a code or description of the processing applied to the image, which the camera or workstation usually writes but PS3.3 defines as free text, as Reconstruction Method is treated; and Energy Window Name (0054,0018), in the items of the NM Isotope Module’s Energy Window Information Sequence (0054,0012) (Section C.8.4.10, Table C.8-10), which PS3.3 calls a user defined name of an energy window, such as its photopeak or a scatter window. A person names the window, so its name can hold anything, while the window’s limits, in Energy Window Range Sequence (0054,0013), and Energy Window Vector (0054,0010), which gives each frame’s window, keep what scatter correction needs without it. Image ID (0054,0400), in the NM Image Module, which PS3.3 calls a user or equipment generated image identifier, can be typed with a name or a record number, so it has the stricter rule for names and identifiers above. Each of the three is Type 3, so each is removed under
basic, and the two descriptions are cleaned under Clean Descriptors. The IODs supported before it use every UID, date, time, datetime, person name, and URL that it uses, so each already has its role or its rule (D-003, D-007). Its 50 other new attributes, 18 of VR US, 12 DS, 10 IS, 8 SQ, and 2 CS, are the vectors, counts, and sequences of its NM Multi-frame, NM Image, NM Isotope, NM Detector, NM Tomo Acquisition, NM Multi-gated Acquisition, NM Phase, and NM Reconstruction Modules, such as Energy Window Vector, Angular Step (0018,1144), and Whole Body Technique (0018,1301), and two attributes of its Multi-frame Overlay Module, none listed in Table E.1-1 or given a rule, which the rule for attributes that no rule covers keeps where it defines them, with a kept sequence’s items handled by their own rules. The IOD is supported (D-010), so the three are among the 196.Surface Segmentation, which the maintainer added to the target coverage on 31 October 2026 (D-010), uses two text attributes that Table E.1-1 omits and no other supported IOD uses, Surface Comments (0066,0004) and Surface Processing Description (0066,000B), both Type 3 and typed by an operator, so both are among the 89 operator-typed labels and text. Its other attributes outside Table E.1-1 are geometry and coded flags, which no rule names and the default keeps.
Parametric Map and Real World Value Mapping, which the maintainer added to the target coverage on 31 October 2026 with the other IODs that RT exports carry (D-010), were reviewed in the same way against every IOD supported before them, need no rule of their own, and are supported (D-010). Neither uses a text attribute, UID, person name, URL, date, time, or datetime that those IODs do not, so each already has its role or its rule (D-003, D-007). They add 11 attributes that no IOD supported before them uses, none listed in Table E.1-1 or given a rule: Parametric Map’s Float Pixel Data (7FE0,0008) and Double Float Pixel Data (7FE0,0009), with their Float Pixel Padding Value (0028,0122), Double Float Pixel Padding Value (0028,0123), Float Pixel Padding Range Limit (0028,0124), and Double Float Pixel Padding Range Limit (0028,0125); its Stored Value Color Range Sequence (0028,1230), with Minimum Stored Value Mapped (0028,1231) and Maximum Stored Value Mapped (0028,1232), from the Palette Color Lookup Table Module; and its Parametric Map Frame Type Sequence (0040,9092); and Real World Value Mapping’s Referenced Image Real World Value Mapping Sequence (0040,9094). The rule for attributes that no rule covers keeps each where its IOD defines it, with a kept sequence’s items handled by their own rules, and the engine handles floating-point pixel data as D-037 and D-046 set. Removal by Type gives each attribute that they use and that Table E.1-1 or a rule gives a compound action an action that it already takes in an IOD supported before them, and the places where a plain X sequesters an instance, Responsible Person and Responsible Organization in the Patient Module, are those of every IOD (D-020).
Enhanced RT Image and Enhanced Continuous RT Image, which the maintainer added to the target coverage on 31 October 2026 (D-010), were reviewed with their support, and are supported (D-010). Their modules are the same but for those of their frames: an Enhanced RT Image has the Multi-frame Functional Groups, Multi-frame Dimension, and Frame Extraction Modules, and an Enhanced Continuous RT Image the Sparse Multi-frame Functional Groups Module, which gives the functional groups of a selection of its frames; both use the same functional group macros (PS3.3 Tables A.86.1.15-1, A.86.1.15-2, A.86.1.16-1, and A.86.1.16-2). Of the text attributes that they use and the IODs supported or reviewed before them do not, four are listed in Table E.1-1, whose actions apply: Radiation Generation Mode Label (300A,067C) D and Radiation Generation Mode Description (300A,067D) Z, in the description of each radiation generation mode, Entity Description (3010,0037) X, and Conceptual Volume Combination Description (3010,000F) Z. The fifth, Conceptual Volume Combination Expression (3010,000C), which Table E.1-1 omits, says how a combined Conceptual Volume is made from its constituents, in the nested list notation of PS3.3 Section 10.34.1.1, such as
(UNION 1 2): only five geometric operators, parentheses, spaces, and the constituents’ indices. It is kept, as Fraction Pattern is, since it is software-generated structure that identifies no one, Table E.1-1 removes the human-readable description beside it, and replacing it would lose which volumes are combined and how; keeping it accepts the residual risk that a writer that does not follow the notation puts other text in it, which review of the run’s retained strings would show (D-017). The two UIDs that they add, Referenced Treatment Position Group UID (300A,0785) and Constituent Conceptual Volume UID (3010,0013), are listed in Table E.1-1 with U and are each the UID of an instance (D-003), and they add no date, time, datetime, person name, or URL. Removal by Type gives each attribute that they use and that Table E.1-1 or a rule gives a compound action an action that it already takes in an IOD reviewed before them, with two exceptions: Instance Creation Date (0008,0012) and Instance Creation Time (0008,0013), which Table E.1-1 gives X/D and X/Z/D, are Type 1 in the Radiotherapy Common Instance Module (PS3.3 Table C.36.4-1), so they take D’s dummy value in these IODs, or are kept or modified under Full Dates and Modified Dates, while the IODs reviewed before them define them only in the SOP Common Module, as Type 3, where they are removed. Every place in these IODs where a plain X falls on a required attribute, or a D on a sequence or a URL, is one that the IODs supported before them have, with the same removal or rule, but for two: Unique Device Identifier (0018,1009), which Table E.1-1 gives X, is removed with its Type 3 UDI Sequence (0018,100A) in the items that describe the acquisition devices, beam limiting devices, accessories, patient support devices, and X-ray filters, as it is elsewhere; and Person Identification Code Sequence (0040,1101), which Table E.1-1 gives D, takes its reviewed dummy item in the Author Identification Sequence (3010,0019) as it does in every other item that identifies a person (D-021). Their 65 other new attributes are codes, numbers, and sequences of the frames’ acquisition, the imaging and treatment devices, the treatment positions, and the Conceptual Volumes named, none listed in Table E.1-1 or given a rule, which the rule for attributes that no rule covers keeps where they define them, with a kept sequence’s items handled by their own rules.The list also gives a rule, ahead of supporting them, to the nine text attributes that Table E.1-1 omits and that, of the IODs that the first supported release supports, Enhanced RT Image, Enhanced Continuous RT Image, and the 16 second-generation RT IODs, only the last 16 use, which the maintainer added to the target coverage on 31 October 2026 (D-010). Six are operator-typed text: Reason for Channel Omission Description (0074,140B), treated as Table E.1-1 treats Reason for Omission Description (300C,0113); Specification Selection Guidance (0082,0033), brief guidance for an operator choosing a constrained parameter’s value; Constraint Violation Condition (0082,0037), which PS3.3 lets be an expression, human-readable text, or another form; Position Acquisition Template ID (3002,0120), treated as Table E.1-1 treats the template’s name and description; Treatment Tolerance Violation Identification (300A,0735), which PS3.3 intends for structured processing but defines as free text, treated as Table E.1-1 treats Treatment Tolerance Violation Description (300A,0734); and Segmentation Creation Template Label (3010,001E), a label that a site gives its template, as it gives RT Tolerance Set Label and RT Prescription Label. Constraint Violation Condition, Position Acquisition Template ID, and Treatment Tolerance Violation Identification are Type 1C where these IODs define them, so removal by Type gives each a dummy value where it is present. Three are kept: Selector Attribute Name (0082,0018) and Selector Attribute Keyword (0082,0019), which PS3.3 requires, for a standard attribute, to be its name and keyword in PS3.6 Table 6-1, so that they name an attribute rather than hold its value; and Intended Start Day of Week (3010,0086), a string of 0s and 1s giving the weekly pattern of fractions at the start of a prescription or radiation set, kept as Fraction Pattern is. Table E.1-1 lists every other text attribute that only these IODs use, with an action that removes or replaces its value. Every UID and every date, time, and datetime that they use has a role (D-003, D-007); of those that the IODs reviewed before them do not use, Creator Version UID (0008,9123) and Selector UI Value (0072,007F), which Table E.1-1 omits, are replaced as the UIDs of instances are, Pertinent SOP Classes in Study (3010,0052) and Pertinent SOP Classes in Series (3010,0053) name SOP Classes and are kept, and the others are listed in Table E.1-1, the dates and times as subject events but for Selector DA Value and Selector TM Value, whose role stays other, as Selector DT Value’s does. The one person name and the one URL that they add are Selector PN Value (0072,006A) and Selector UR Value (0072,0071), which Table E.1-1 gives D. Their 263 other new attributes are codes, numbers, indices, and sequences of the radiations, their devices, prescriptions, and delivery, the thickness maps of a compensator and the edge data of a block, and the binary values of VR OD, OF, OL, OV, and OW that a constraint can hold, which Table E.1-1 does not list, none given a rule, which the rule for attributes that no rule covers keeps where these IODs define them, with a kept sequence’s items handled by their own rules. Removal by Type, and the places where a plain X falls on a required attribute, a plain Z on a Type 1 attribute, or a D on an attribute of a VR without a dummy value, such as a sequence or a URL, match those of the IODs reviewed before them, with the same removal, in all but these places, outside a sequence that the Basic Profile removes: Operator Identification Sequence (0008,1072), which Table E.1-1 gives X/D, is Type 1 in Override Sequence (3008,0060) of the four records that record treatment tolerance violations, C-Arm Photon-Electron Radiation Record, Tomotherapeutic Radiation Record, Robotic-Arm Radiation Record, and RT Radiation Salvage Record, so it resolves to D; Referenced Study Sequence (0008,1110), which Table E.1-1 gives X/Z, is Type 1 in three reference items of RT Physician Intent and RT Patient Position Acquisition Instruction, so it resolves to D, as D-021 records; a sequence has no dummy value, so either sequesters its instance until a reviewed rule gives it items (D-021). Selector AE Value (0072,005E), Selector AS Value (0072,005F), Selector OB Value (0072,0065), Selector UN Value (0072,006D), and Selector UR Value, which Table E.1-1 gives D, are Type 1C where a constraint of RT Patient Position Acquisition Instruction holds a value of their VR, and no value of those VRs has a dummy value, so such an instance is sequestered (D-021). RT Accessory Holder Slot ID (300A,0611), which Table E.1-1 gives Z, is Type 1 in RT Accessory Holder Slot Sequence (300A,0610) of five of them, so it takes the dummy value (D-020). Patient Treatment Preparation Procedure Parameter Description (300A,078E), which Table E.1-1 gives X, is Type 2 in the Type 2 Patient Treatment Preparation Procedure Sequence (300A,0790) at the top level of RT Treatment Preparation, and Prior Treatment Dose Description (3010,0061), which it also gives X, is Type 2 in the Type 1 RT Prescription Sequence (3010,006B) of RT Physician Intent, so no Type 3 sequence encloses either and a plain X sequesters the instance, as it would Source Manufacturer’s in Recorded Source Sequence (D-020). Patient Setup Photo Description (300A,0794) is Type 2 in the Type 3 Referenced Patient Setup Photo Sequence (300A,078C) at the top level of RT Treatment Preparation, which its plain X removes, and the position acquisition template’s name, Type 1, and description, Type 2, are in the Type 3 Position Acquisition Template Identification Sequence (3002,011F), which theirs removes. The change that supports each IOD settles where it sequesters (D-020, D-021). RT Segment Annotation, RT Radiation Set, and the C-Arm Photon-Electron, Tomotherapeutic, and Robotic-Arm Radiation IODs are supported (D-010), as are RT Beams Delivery Instruction, RT Brachy Application Setup Delivery Instruction, and RT Radiation Set Delivery Instruction: of the nine, RT Segment Annotation uses Segmentation Creation Template Label, RT Radiation Set uses Intended Start Day of Week, and RT Brachy Application Setup Delivery Instruction uses Reason for Channel Omission Description, which are among the 196, and of the places above, only RT Accessory Holder Slot ID’s, in C-Arm Photon-Electron Radiation and Robotic-Arm Radiation, is in them, where it takes the dummy value.
The list also gives a rule, ahead of supporting them, to the seven text attributes that Table E.1-1 omits and that, of the IODs that the first supported release supports or that were reviewed before them, only the six softcopy Presentation State IODs use, which the maintainer’s pick of 31 October 2026 brought into the target coverage (D-010). Five are operator-typed text: Mask Operation Explanation (0028,6190), a free-form explanation of a mask subtraction (PS3.3 Section C.7.6.10); Graphic Layer Description (0070,0068), a free-text description of a graphic layer’s contents (Section C.10.7); Graphic Group Label (0070,0207) and Graphic Group Description (0070,0208), which label and describe a group of annotations (Section C.10.11); and Tick Label (0070,0289), the text of a tick of a ruler or axis drawn over the image (Section C.10.5), which takes the actions that Table E.1-1 gives Unformatted Text Value (0070,0006), the text of a text object, since a viewer shows it with the image as it shows that text. Two are technical values, which are kept: Font Name (0070,0227), the name of a typeface of the kind that Font Name Type (0070,0228) names, and CSS Font Name (0070,0229), a CSS generic font family (Table C.10-5a). Graphic Group Label and Tick Label are Type 1 where these IODs define them, so they take D’s dummy value; the other three operator-typed attributes are Type 3 there, so they are removed. Tick Label, the font names, and Unformatted Text Value are within the Graphic Annotation Sequence (0070,0001), whose D sequesters the instance that holds it (D-010, D-041), so they reach no written file until the maintainer decides how an annotated Presentation State is released. Every UID, person name, and URL that these IODs use already has a role or a rule, and the only dates and times that the IODs reviewed before them do not use, Presentation Creation Date (0070,0082) and Time (0070,0083), are listed in Table E.1-1 as subject events, which the date options keep or shift (D-007). Their other attributes are kept by the default for their VRs where these IODs define them, below: code strings, numbers, and the binary Fill Pattern (0070,0256) of the shutters, masks, displayed areas, spatial transformations, LUTs, graphic layers, and annotations’ geometry and style, none of which a person types as text.
Encapsulated PDF, which the maintainer added to the target coverage on 31 October 2026 (D-010), was reviewed in the same way, against every IOD that the first supported release supported then, and is supported (D-010). It uses eight text attributes that Table E.1-1 omits and those IODs do not, each with a rule. Document Title (0042,0010), which PS3.3 does not constrain and which can be copied from the Title entry of the PDF’s document information dictionary (PS3.3 Table C.24-2), is operator-typed text: Type 2, so it is emptied, and cleaned under Clean Descriptors. MIME Type of Encapsulated Document (0042,0012), which the IOD fixes as application/pdf (PS3.3 Section A.45.1.4.1), and List of MIME Types (0042,0014) name formats, and are kept. In the SC Equipment Module, which describes the equipment that captured or converted the document, Secondary Capture Device Manufacturer (0018,1016), Secondary Capture Device Manufacturer’s Model Name (0018,1018), and Secondary Capture Device Software Versions (0018,1019) are device identity: that equipment can be a site’s own scanning, printing, or reporting system, whose name, model, and software the site chooses, as the manufacturer of an MR coil can be a site that builds its own, so they are removed by Type and kept under Retain Device Identity, unlike Manufacturer, Manufacturer’s Model Name, and Software Versions. The default removed them in every IOD before they had a rule, and the Basic Profile still does. Video Image Format Acquired (0018,1022) and Digital Image Format Acquired (0018,1023) name the signal and interface formats that it captured, and are kept. Table E.1-1 lists the one other text attribute that only it uses, Secondary Capture Device ID (0018,1010), which it removes, and keeps under Retain Device Identity. It uses no UID, date, time, datetime, or person name that those IODs do not, and one URI, Relative URI Reference Within Encapsulated Document (0068,7005), Type 1C in the items of Referenced Image Sequence (0008,1140) and Referenced Instance Sequence (0008,114A) of its Encapsulated Document Module, where removal by Type needs a dummy value, which a URI has none of, so an Encapsulated PDF that holds it is sequestered. Encapsulated Document Length (0042,0015) and Document Class Code Sequence (0040,E008), which no list covers, take the default, which keeps them, with the code sequence’s items under their own rules, and Table E.1-1 gives Encapsulated Document (0042,0011) itself D (Architecture item 7).
Patient’s Birth Date in Alternative Calendar (0010,0033) and Patient’s Death Date in Alternative Calendar (0010,0034) are among the 196: their VR is LO, but they hold dates. They are removed (X), whatever group rule would otherwise apply. Each is Type 3 in the Patient Module of the first supported release’s IODs.
De-identification Method (0012,0063), which Table E.1-1 also omits, is among the 196 too. The engine writes it itself: it keeps the existing values and adds its own, as D-012 sets.
A text attribute that the list does not cover is removed by default: X/Z/D, resolved by Type.
The maintainer decided on 1 October 2026 the rules for the other attributes that Table E.1-1 omits:
Of the 12 URI and URL attributes, of VR UR, that the table omits, URN Code Value (0008,0120), which holds a code’s value where that value is a URN or URL, and Coding Scheme URL (0008,010E) are kept (K), like Code Value and Coding Scheme Designator, since they name coding concepts and schemes. The maintainer decided this on 1 October 2026. URN Code Value is Type 1C in the Basic Code Sequence Macro (PS3.3 Table 8.8-1a), and Coding Scheme URL is Type 1 in the items of Coding Scheme Resources Sequence (0008,0109), which is Type 3 within the Type 3 Coding Scheme Identification Sequence (0008,0110) of the SOP Common Module.
Each of the other ten gets X/Z/D, resolved by Type. The first supported release’s IODs use four of them: Retrieve URL (0008,1190), Pixel Data Provider URL (0028,7FE0), Retrieve URI (0040,E010), and Relative URI Reference Within Encapsulated Document (0068,7005). The other six are Stored Instance Base URI (0008,0407), Folder Access URI (0008,0408), File Access URI (0008,0409), Filename in Container (0008,040B), Storage URL (0040,4073), and Contact URI (0074,100A).
Seven sequences whose content can identify an institution or other patients or say something about the patient get X/Z/D, resolved by Type: Requesting Service Code Sequence (0032,1034), the “Institutional department, unit or service where the request initiated” (PS3.3 Table C.7-3, General Study Module); Patient’s Size Code Sequence (0010,1021) (Table C.7-4a, Patient Study Module); Issuer of Patient ID Qualifiers Sequence (0010,0024) (Table 10-18, the Issuer of Patient ID Macro, which the Patient Module includes), which holds Assigning Facility Sequence (0040,0036), Assigning Jurisdiction Code Sequence (0040,0039), and Assigning Agency or Department Code Sequence (0040,003A); Issuer of Accession Number Sequence (0008,0051) (Table C.7-3); Reason For Performed Procedure Code Sequence (0040,1012) (Table C.7-3); and Source Patient Group Identification Sequence (0010,0026) and Group of Patients Identification Sequence (0010,0027) (Table C.7-1, Patient Module).
ICC Profile (0028,2000) and MAC Parameters Sequence (4FFE,0001) get X/Z/D, resolved by Type, and so does Color Space (0028,2002), which names the colour space of the ICC profile and would otherwise be kept as a code string, since the profile is removed or replaced under every option and a kept Color Space could contradict the profile written.
Patient’s Body Mass Index (0010,1022), Measured AP Dimension (0010,1023), and Measured Lateral Dimension (0010,1024), measures of the patient’s body like Patient’s Size (0010,1020) and Patient’s Weight (0010,1030), which Table E.1-1 removes (X), get X/Z/D, resolved by Type. They are Type 3 in the Patient Study Module (PS3.3 Table C.7-4a), so they are removed in the first supported release’s IODs under every option, including Retain Patient Characteristics, as Patient’s Size Code Sequence is.
Series Number (0020,0011), a number that identifies a series, gets X/Z/D, resolved by Type, under every option, and wherever Z or D applies, it takes its rank among the distinct Series Numbers of the study that holds the series it numbers, as the maintainer decided on 10 October 2026. The run’s first pass records each Series Number that an instance holds where its IOD defines one, with the Series Instance UID of the series it numbers, the instance’s own at the top level and the item’s own in an item, and finds the study of that series among the run’s instances; each Series Number takes the numbering of all the values that number a series of that study. Each distinct number, read as one Integer String (PS3.5 Section 6.2), takes its rank in ascending order from 1, so equal numbers share a rank and the ranks have no gaps. A value that is empty, is not one Integer String, or has no rank, as where the series it numbers has no instance in the run or has instances in several studies, is emptied under Z and given the dummy value of D-021 under D. In every IOD of the first supported release, Series Number is Type 2 in the General Series or RT Series Module, where Z applies, and Type 1 only in the SR Document Series Module of the Structured Reports, in the Segmentation Series Module, and in the items of Source Series Information Sequence (3006,004C) of the Structure Set Module, where D applies; an item that names a series of the run, of whichever study, takes the rank that the series’ own instances take, and one that names a series that the run does not hold takes the dummy value, since a rank in another study’s numbering would number that series differently from its own instances. The numbering spans one run, as the values that a run’s ephemeral key generates do (D-004), so a study de-identified in two runs can number its series differently. A project key, whose values stay consistent across runs, would need the study’s numbering kept with its subject profile, or every series of the study in each run, for a series to keep its number.
The seven sequences and MAC Parameters Sequence are Type 3 wherever the first supported release’s IODs define them, so each is removed there, as are Retrieve URL and Retrieve URI, which those IODs require only inside sequences that Table E.1-1 removes. ICC Profile is Type 3 there too, except at the top level of the Enhanced CT Image, Enhanced MR Image, Enhanced MR Color Image, Segmentation, and Nuclear Medicine Image IODs, where it is Type 1, so D replaces it there with the profile of D-021’s reviewed rule: the source cleaned of everything but its colorimetry, or the fixed sRGB profile where the source cannot be cleaned. The third, Pixel Data Provider URL, is Type 1C in the Image Pixel Module of RT Dose and of each image IOD of the first supported release, all but MR Spectroscopy, and the module requires it only for the JPIP Referenced transfer syntaxes, which the first supported release does not read. There X/Z/D resolves to D, for which D-021 gives UR no dummy value, so an instance with such a value there is sequestered unless a reviewed rule gives one.
Any other attribute of the pinned dictionary that no rule covers, after Table E.1-1, these rules, the UID roles (D-003), the rule for text above, and the engine’s own removals and writes (D-012, D-013), is kept if its VR is CS, AT, or a numeric VR (DS, IS, FL, FD, SL, SS, SV, UL, US, or UV). A sequence, or a binary value of VR OB, OD, OF, OL, OV, OW, or UN, is kept only where the IOD defines the attribute at that place, and removed elsewhere, so that a sequence that no supported IOD defines, such as Discharge Diagnosis Code Sequence (0038,0044), cannot keep the codes in its items. The attributes in a kept sequence’s items are handled by the same rules. Such an attribute of any other VR is removed; in 2026d there is none, since every AE and AS attribute is in Table E.1-1. An attribute absent from the pinned dictionary is removed, as Architecture item 2 sets.
The maintainer decided on 6 October 2026 how the first supported release treats an institution’s name in local codes and private creators. Codes of a local coding scheme, whose Coding Scheme Designator begins with “99” or is “L”, which PS3.3 Section 8.2 says HL7 V2 defines as private or local Coding Schemes, keep their Code Value, Coding Scheme Designator, and Code Meaning, like every other code, although they can carry an institution’s name or abbreviation. The conformance statement says so, says that each such value is listed among the QC pack’s retained strings, and says that a
public-releaserun is ready for release only where an external risk assessment states how such values were assessed and whether it supports keeping them (D-017). Private Data Element Characteristics Sequence (0008,0300), whose items hold Private Creator Reference (0008,0302), is removed whenever no private attribute is kept (D-028). Selector Attribute Private Creator and Selector Sequence Pointer Private Creator are kept, as above.The Common Instance Reference Module’s two sequences, Referenced Series Sequence (0008,1115) and Studies Containing Other Referenced Instances Sequence (0008,1200), are kept by the rule for sequences above, with their UIDs replaced (D-003), except that both are removed, with their items, where the instance keeps no other reference to an instance: no Referenced SOP Instance UID (0008,1155) or Multi-frame Source SOP Instance UID (0008,1167) with a value, in an item of any sequence but theirs, other than one that names a study in the items of Referenced Study Sequence (0008,1110) or RT Referenced Study Sequence (3006,0012). PS3.3 Section C.12.2 makes both Type 1C, “Required if this Instance references Instances in this Study” and “Required if this Instance references Instances in other Studies”, without “May be present otherwise”, so PS3.5 Section 7.4.2 does not allow them once the Basic Profile has removed every reference that met those conditions, as X/Z/U* removes Referenced Image Sequence (0008,1140) and Source Image Sequence (0008,2112) where they are Type 3 (D-020). Where a reference remains, both are kept. The dummy item that D writes for Referenced Performed Procedure Step Sequence (0008,1111) counts as one (D-021). Every IOD of the first supported release but the Structured Reports, whose SR Document General Module references their evidence instead, includes the module, as user-optional but for Spatial Registration and Deformable Spatial Registration, which make it mandatory, so removing both sequences leaves an instance without the module, or, in a registration, with the module but neither of its conditional sequences, which its IOD allows. The check of each written instance against its IOD (D-020) allows their removal only where the output holds no such reference with a value. The softcopy Presentation State IODs do not include the module, and their Presentation State Relationship Module makes Referenced Series Sequence Type 1 at the top level, with the images that the presentation applies to in its items: there it is that module’s sequence, not this one, so it is kept, with its UIDs replaced, and never lapses; an attribute counts as the module’s only where no other module of the instance’s IOD defines it there.
Rationale. E.1.1 leaves the de-identifier responsible for identifying information in these attributes. The list is auditable and consistent with how Table E.1-1 treats similar attributes: RT Plan Label is D, RT Plan Name and Beam Description X, and ROI Name Z, all C under Clean Descriptors, and Treatment Machine Name is X/Z, and K under Retain Device Identity. Removing every omitted text attribute that is not listed as safe was rejected: it would replace Code Value (0008,0100), which is Type 1C in the Basic Code Sequence Macro (PS3.3 Table 8.8-1a), and so destroy coded meaning, and it would strip technical values that are useful and not identifying, such as Convolution Kernel. Keeping them all was rejected because it fails E.1.1: beam names and comments often contain patient names and dates. Accessory identifiers are kept only under Retain Device Identity:
tps-importkeeps them as typed, including those of accessories usually made for one patient, such as Compensator ID. Names and identifiers of people, organisations, records, and networks are removed under every option, as Table E.1-1 removes comparable attributes, such as Operators’ Name, Clinical Trial Sponsor Name, Issuer of Patient ID, and Container Identifier, under every option, and keeps Institution Name only under Retain Institution Identity, which retains the institution where the acquisition was performed, not the other organisations that these attributes name (D-044); Mapping Resource Name is among them because PS3.3 Section 8.4 says it may denote the institution or organisation that specified the value set. Accessory Code and Tray Accessory Code are removed under every option because PS3.3 describes each as an identifier intended to be read by a device such as a bar-code reader, nearly as it describes Device Alternate Identifier (3010,001B), which Table E.1-1 empties under every option, including Retain Device Identity. Table E.1-1 at most cleans network identities, such as Station AE Title, even under Retain Device Identity, so NTP Source Address is removed under every option; and it cleans Overlay Comments only under Clean Graphics, under which the engine removes it (D-041), so Overlay Description and Overlay Label are removed under every option too. Manufacturer, Manufacturer’s Model Name, and Software Versions are kept because they identify products, which every site that uses them shares, rather than devices: Table E.1-1 omits them while listing Device Serial Number, and Manufacturer is Type 1 in Contributing Equipment Sequence (PS3.3 Table C.12-1). A device made in-house can carry the hospital as its Manufacturer. That residual risk is accepted because the value names an institution, not a patient:public-releasereviews every distinct retained string, and is ready for release only where an external risk assessment states whether it supports keeping such values (D-017), but the other presets keep such a value without review or assessment. A URI or URL can carry host names and file paths, so the UR attributes are removed by Type, as the Basic Profile removes or replaces the three UR attributes that Table E.1-1 lists, such as Display URI (0040,E012). URN Code Value and Coding Scheme URL are the exceptions: they name coding concepts and schemes, as Code Value and Coding Scheme Designator do, and removing them where they are required would sequester an instance, since UR has no dummy value, although Coding Scheme URL is often the public URL of a published coding scheme. A local scheme’s URL can name an institution’s host; that residual risk is accepted, as for Manufacturer, because it names an institution, not a patient. The first five of the seven sequences hold codes or identifiers like those of attributes that Table E.1-1 removes or empties: it gives Requesting Service (0032,1033), Patient’s Size (0010,1020), and Issuer of Patient ID (0010,0021) X, Accession Number (0008,0050) Z, and Reason for Visit Code Sequence (0032,1067) and the other reason and diagnosis code sequences X. Table E.1-1 keeps Patient’s Size under Retain Patient Characteristics, whichtps-importselects, whereas Patient’s Size Code Sequence is removed under every option. The difference is deliberate: E.3.7 requires the option’s characteristics to be retained “as described in Table E.1-1”, which does not list the sequence, so removing it is consistent with the option, and Architecture item 2 lets a rule give an action under an option only to a text attribute or to a date, time, or datetime. The other two, Source Patient Group Identification Sequence and Group of Patients Identification Sequence, hold Patient IDs other than the instance’s own, of the subjects in an instance that holds a group of subjects acquired together, and of the group’s source instances, from which an instance was extracted (PS3.3 Table C.7-1); removing them avoids deciding pseudonyms for patients outside the export. MAC Parameters Sequence describes the digital signatures that Table E.1-1 removes with Digital Signatures Sequence (FFFA,FFFA), and ICC Profile holds a file in another format, which the engine parses only to clean it where D-021’s reviewed rule replaces it. Series Number is a number like those that the rule for attributes that no rule covers keeps, but nothing constrains what is written there beyond its VR: in MIDI-B’s synthetic Validation collection, most released instances held a date of eight digits as their whole Series Number, and the residual search does not search numbers (D-027), so keeping it released the date. Table E.1-1 empties Study ID (0020,0010), the study’s own number (Z), and Z and D each allow a dummy value consistent with the VR (Table E.1-1a), as the pseudonyms of Patient ID and Patient’s Name are (D-005), so the rank replaces the number: it keeps the order of the series within a study, by which viewers sort them and people name them, and carries nothing else of the source value. Emptying it was rejected because it loses that order, and the Basic Profile removes Series Description (0008,103E) too, so the series of a study could then be told apart only by their content and UIDs. Emptying only values that read as dates was rejected: it would be the only action that depends on what a value reads as, and would miss an identifier of another shape. Ranking needs the study’s other instances, which the first pass already reads before anything is written; an instance de-identified outside a run ranks only the values that number its own series. Any other attribute is kept because Table E.1-1 “defines the minimum actions required for conformance” (Note 5 after Table E.1-1a), and PS3.15 notes that “it is usually safe to assume that code strings do not contain identifying information” (Note 9), and that the same is usually true of coded sequence entries, except codes for providers and staff (Note 10). Keeping a sequence requires “recursively applying the Profile rules to each Data Set in each Item of the Sequence” (Table E.1-1a), so its items get the same rules. A binary value of an attribute that the IOD does not define at that place has no meaning there that the engine can check, so it is removed. The Common Instance Reference Module’s sequences are removed only where no reference remains because that can be decided from the data set’s structure, as the engine’s plan is made; telling whether a remaining reference names an instance of this study or of another needs the UIDs’ values, so where one remains both are kept, and an instance whose remaining references all name instances of other studies keeps a Referenced Series Sequence whose condition does not hold. The dummy item of Referenced Performed Procedure Step Sequence counts as a reference because PS3.3’s “references Instances” does not restrict itself to composite instances; the module cannot list a procedure step, so counting it only keeps the module where it may have lapsed, as before this rule, and never removes one that is needed. Removing both wherever dciodvfy reports them was rejected: its condition counts only Source Image, Source Instance, Referenced Image, and Referenced Instance Sequences and a few others, while PS3.3’s counts a reference from any module, such as Referenced Image Evidence Sequence (0008,9092) or Referenced Defined Protocol Sequence (0018,990C), so removing them there would make the output invalid.Tests. Every text attribute that Table E.1-1 omits and a supported IOD uses has a rule with a note, and a regenerated table that adds one fails to load until it has a rule; each of the 31 text attributes that only the CT, MR, and PET IODs added on 7 October 2026 use has a rule in its group; each of the 16 text attributes that, of those IODs and the IODs supported before them, only the five IODs of the target coverage reviewed ahead of support use has a rule in its group, and every UID and every date, time, and datetime that those IODs use has a role, the UIDs and dates that none of the IODs supported before them uses being listed in Table E.1-1 as UIDs of instances and as subject events, and of the five only the two registration IODs, RT Beams Treatment Record, and RT Image are supported; each of the two text attributes that the four Radiation Dose SR IODs use, and the IODs reviewed before them do not, and that Table E.1-1 omits is operator-typed text, and the three that it lists remove or replace their values, and every UID and every date, time, and datetime that those IODs use has a role, those that neither the supported nor the target IODs use being listed in Table E.1-1, with Selector DT Value’s role other; the Basic Text, Enhanced, Comprehensive, Comprehensive 3D, and Extensible SR IODs, and the other fourteen Structured Report and Key Object Selection IODs of PS3.3, use no attribute that those IODs and the ones reviewed before them do not; each of the 13 text attributes that only RT Ion Plan and RT Ion Beams Treatment Record use, of the IODs supported or reviewed before them, has a rule in its group, which every policy applies with the action of its group’s option, and removal by Type gives each one removed where these IODs define it the action that its note says, a dummy value only where it is Type 1; every UID and every date, time, and datetime that those IODs use has a role, and the IODs reviewed before them use every UID, date, time, datetime, person name, and URL that they use; and the 109 other attributes that only they use are codes, numbers, and sequences, none listed in Table E.1-1 or given a rule, which every preset keeps where these IODs define them, and both IODs are supported; RT Brachy Treatment Record and RT Treatment Summary Record are generated and supported, RT Treatment Summary Record’s modules are among RT Beams Treatment Record’s, and RT Brachy Treatment Record adds only the RT Brachy Session Record Module, whose text attributes RT Plan’s RT Brachy Application Setups Module or RT Beams Treatment Record’s RT Beams Session Record Module use; neither uses a text attribute that the IODs supported or reviewed before them do not, and each text attribute they use that Table E.1-1 omits has a rule with a note; removal by Type gives each attribute they use an action that it takes in an IOD reviewed before them but Source Serial Number, which it empties in Recorded Source Sequence; a plain X on a required attribute, a plain Z on a Type 1 attribute, or a D on a sequence or URL falls, outside a removed sequence, only where it does in the IODs reviewed before them, with the same removal, but for Source Manufacturer, which a plain X empties in Recorded Source Sequence, where its removal would sequester the instance; every UID and every date, time, and datetime that they use has a role, the IODs reviewed before them use every UID, person name, and URL that they use, and the four dates and times that they add are the safe position’s, which Table E.1-1 lists with D, K under Full Dates, and C under Modified Dates, as subject events; and the 21 other attributes that only RT Brachy Treatment Record uses are codes, numbers, and sequences of its RT Brachy Session Record Module, none listed in Table E.1-1 or given a rule, which every preset keeps where it defines them; Enhanced RT Image and Enhanced Continuous RT Image are generated and supported, and differ only in the modules that describe their frames, with the same functional group macros; the four text attributes that they add, and the IODs supported or reviewed before them do not use, that Table E.1-1 lists take its actions, and Conceptual Volume Combination Expression, which it omits, is kept under every option, with a note; removal by Type gives each attribute they use an action that it takes in an IOD reviewed before them but Instance Creation Date and Instance Creation Time, which are Type 1 in their Radiotherapy Common Instance Module and so take D, K under Full Dates, and C under Modified Dates; every UID and every date, time, and datetime that they use has a role, the IODs reviewed before them use every date, time, datetime, person name, and URL that they use, and their two new UIDs are listed in Table E.1-1 with U as UIDs of instances; the 65 other attributes that only they use are codes, numbers, and sequences, none listed in Table E.1-1 or given a rule, which every preset keeps where they define them; and Radiation Generation Mode Label and Description and Referenced Treatment Position Group UID, which they define only five items deep, take their actions there, while a label nested one level less deep, where no supported IOD defines it, is not kept; the 16 second-generation RT IODs are generated, and RT Segment Annotation, RT Radiation Set, the three radiations, and the three delivery instructions are the only ones of them supported, each of the nine text attributes that only they use, of the IODs supported or reviewed before them, and that Table E.1-1 omits has a rule in its group, which every policy applies with the action of its group’s option, the others that only they use being listed in Table E.1-1 with an action that removes or replaces their values, and removal by Type gives each one removed where these IODs define it the action that its note says, a dummy value only where it is Type 1C; every UID and every date, time, and datetime that they use has a role, those that the IODs reviewed before them do not use having the roles above, and the one person name and one URL that they add are Selector PN Value and Selector UR Value, which Table E.1-1 gives D; the 263 other attributes that only they use are codes, numbers, binary values, and sequences, none listed in Table E.1-1 or given a rule, which every preset keeps where these IODs define them; and a plain X on a required attribute, a plain Z on a Type 1 attribute, or a D on an attribute of a VR without a dummy value falls, outside a removed sequence, only where it does in the IODs reviewed before them, with the same removal, but for the places above in Override Sequence, the three reference items, the constraints’ selector values, RT Accessory Holder Slot Sequence, RT Treatment Preparation, and RT Prescription Sequence; Nuclear Medicine Image is generated and supported, and of the three text attributes that only it uses, of the IODs supported before it, Processing Function and Energy Window Name are operator-typed text and Image ID is removed under every option, each Type 3 where it defines them, so that removal by Type removes it; it uses no UID, date, time, datetime, person name, or URL that those IODs do not, and its 50 other new attributes, by VR, are none listed in Table E.1-1 or given a rule, so every preset keeps them where it defines them; each group gets its actions under the Basic Profile, Clean Descriptors, and Retain Device Identity, and the names and identifiers are removed under every option; a malformed option action, or one on a rule whose group allows none, is rejected; coded values keep their meaning; both alternative calendar dates are removed under every preset; De-identification Method keeps its existing values and gains the engine’s; a text attribute without a rule is removed, or emptied or given a dummy value where its Type requires; URN Code Value and Coding Scheme URL are kept under every option, with a note; each other UR attribute that Table E.1-1 omits, each of the seven sequences, ICC Profile, Color Space, and MAC Parameters Sequence has X/Z/D with a note, Series Number has X/Z/D under every option, which resolves to Z where the first supported release’s IODs define it but in the items of Source Series Information Sequence, where it is Type 1 and resolves to D, and wherever Z or D applies it takes its rank in the numbering that the run builds for the study that holds the series it numbers, so that an item naming a series of another study takes that series’ own rank, while a value without a rank, including one in an item that names a series that the run does not hold, is emptied under Z and given the dummy value under D, and no date written there reaches the output, and each is removed where the first supported release’s IODs make it Type 3, under every option, as Patient’s Size Code Sequence is under Retain Patient Characteristics, while a UR value that the IOD requires sequesters its instance; an attribute that no rule covers is kept if its VR is CS, AT, or a numeric VR; a sequence or a binary value is kept where the IOD defines the attribute at that place and removed elsewhere, with the attributes in a kept sequence’s items handled by their own rules, and an Encrypted Attributes Sequence is removed with its items (D-013); such an attribute of any other VR is removed; and an attribute absent from the pinned dictionary is removed; and the Common Instance Reference Module’s two sequences are removed, with their items, where no other reference to an instance with a value is kept, an empty one, one that names a study, and the module’s own not counting, and both are kept where one is, including one within a nested Referenced Series Sequence and the dummy item of Referenced Performed Procedure Step Sequence, while the check against the IOD allows their removal only where the output holds no such reference.
D-023: Dates and times that Table E.1-1 omits#
Decision. Every date, time, and datetime attribute of the pinned dictionary that Table E.1-1 omits gets X/Z/D under the Basic Profile, as a reviewed L2 action, besides the role that D-007 gives it. In 2026d there are 15: three general attributes, Item Inventory DateTime (0008,0404), Expiration DateTime (0008,0416), and Study Update DateTime (0008,041F); eight that PS3.6 marks DICONDE; and four that it marks DICOS. As the table does for every date and time it lists except Patient’s Birth Date, Patient’s Birth Time, and GPS Time Stamp, each rule also gives K under Retain Longitudinal Temporal Information with Full Dates and C under Modified Dates, which modifies the attribute by its role (D-007), and no action under any other option, so Retain Device Identity keeps neither Date of Gain Calibration (0014,3076) nor Time of Gain Calibration (0014,3077) and conflicts with Modified Dates on neither.
Rationale. This is consistent with the Basic Profile removing every date it lists, and none of the 15 appears in the first supported release’s IODs, so the choice costs nothing there. Keeping them under the Basic Profile was rejected because dates are quasi-identifiers; they are kept only under Full Dates, as the table keeps the dates it lists. Acting on them by temporal role under the Basic Profile was rejected as more nuance than the risk justifies.
Tests. Each of these attributes has X/Z/D under the Basic Profile, with a note, K under Full Dates, and C under Modified Dates, and every policy gives it C exactly when it selects Modified Dates; and a regenerated dictionary that adds a date, time, or datetime that Table E.1-1 omits fails the tests until the attribute has a rule.
D-024: De-identification method digest#
Decision.
The de-identification method digest is a SHA-256 identifier of the policy and the PyMedPhys implementation that determine the de-identification method. It covers the policy (D-011) and everything the engine could apply, whether or not the selected options use it: PyMedPhys’s version; the content digest of every generated table; every L2 rule; every L3 rule, or their absence; the digest of the entries of the TG-263 vocabulary that descriptor cleaning matches ROI names against (D-009), or the absence of a vocabulary; the keyed digest of the reviewed-names list whose decisions descriptor cleaning applies (D-009), or the absence of a list; the text finder’s class and its description of its method under the Clean Pixel Data Option (D-037), or the absence of a finder; the keyed digest of the reviewed region rules whose regions that option blacks out beside the finder’s (D-037), or the absence of rules; under the Retain Safe Private Option, the list whose rules settle private attributes, the reviewed rules or TCIA’s Private Tag Dictionary (D-035), or, without the Option, the absence of one; every parameter of generated values; the source and rule files of the de-identification package; and the source files of PyMedPhys’s modules outside the package that it imports. Each instance records it in De-identification Method (D-012) as 64 lowercase hexadecimal digits.
A generated table’s content digest is computed from its rows and must match the digest the table records, as its loader requires (D-001).
The source and rule files are every
.py,.toml,.json,.csv,.txt,.html,.css, and.jsfile of thepymedphys._dicom.deidentifypackage, at any depth: its modules, its L2 rule files and the requirements register beside them, its generated tables, TCIA’s Private Tag Dictionary with its notice (D-035), and the redaction review app’s page (D-059). Each is read as bytes, with CRLF line endings normalised to LF, so a Windows checkout gives each file the same digest.__pycache__and names that start with.within the package, such as the caches that tools write, are left out. The digest is refused when none of these files can be found, or when they do not include the module that computes the digest, so that an installation whose files cannot be read never gives a digest that covers none of its code. These files and the generated tables are read once per process, when the first digest is computed, and stand for the engine as read then, not as imported. An edit after the first digest is not seen until the process restarts, so every instance of a run carries the same digest; an edit between importing the engine and the first digest can give the old code the new files’ digest. Editing or reloading the engine’s modules in a running process, for example withimportlib.reloador Jupyter’s autoreload, is not supported, and the digest is then not guaranteed to match the code that runs. The engine is to compute the digest before it processes anything, so that the digest stands for the code that runs.The outside modules are every module of PyMedPhys outside the package that its modules import, directly or through one another, such as
pymedphys._geometry, which clips contours,pymedphys._nomenclature.roi_list, which matches ROI names, andpymedphys._version, listed by their paths within PyMedPhys; a package in the list stands for each of its files of a covered type at any depth. Each is read in the same way and at the same time as the package’s files, and named in the serialisation bypymedphys/and its path within PyMedPhys, such aspymedphys/_geometry/polygons.py. The digest is refused when one cannot be found. A package’s__init__.pythat runs only because one of its modules is imported is left out, as ispymedphys/__init__.py, which imports PyMedPhys’s public API, none of which the engine calls.The digest is computed over a canonical serialisation labelled with its format,
pymedphys-deid-method-digest/7: one JSON object encoded as UTF-8, with every object’s members sorted by key, no whitespace outside text, every character other than",\, and the control characters written as itself, and integers in decimal. Its members areformat,engine_version,policy,tables,l2_rules,l3_rules,vocabulary,reviewed_roi_names,reviewed_descriptors,technique_vocabulary,text_finder,pixel_region_rules,safe_private_list,generated_values, andfiles. Dataclasses and mappings are objects, sequences are arrays in their own order, and enumerations are their values. The parameters of generated values, and the members of the text finder’s description, have different types, so each is a pair of its type and value, such as["int", 52], with floating-point numbers and bytes in hexadecimal, and a set’s members are sorted. A value of any other type is rejected. A change to the serialisation takes a new format label.There are no L3 rules yet, so the serialisation records their absence as
null, as it does an absent vocabulary, and adding them will change every digest.The runtime environment is not an input to the method digest, apart from the text finder’s under the Clean Pixel Data Option (next item). The Python implementation and version, and the versions of pydicom and tomlkit, are provenance of the execution rather than identity of the method, and are recorded separately (D-012, D-029). The same method, implemented by the same PyMedPhys code and resources, therefore has the same method digest in every supported runtime environment, except that a run under Clean Pixel Data has one for each runtime of its text finder. Of PyMedPhys’s own source tree outside the package, vendored code such as apipkg included, the source files of the modules that the package imports are inputs, as the item on outside modules describes. Of third-party software installed separately, only what a text finder’s own description of its method names is an input: for the text detector, the SHA-256 of its model, the version of ONNX Runtime with the names of the distributions that install it, and the versions of NumPy and SciPy.
The one runtime that is an input is that of the text finder (D-037). The
text_findermember is the finder’s class, by module and qualified name, with a copy of its own description of its method, both read once when the transform is made, ornullwithout a finder. The class keeps a finder that gives another finder’s description, such as a wrapper or a subclass of the text detector, from being taken for it, and the copy gives the markers and the release report one description. The text detector describes its method as the SHA-256 of its model; the version of ONNX Runtime that runs it, with the distributions that install it, sinceonnxruntimeandonnxruntime-gpugive the same version; the versions of NumPy and SciPy, which scale, render, and box each frame; its detection parameters; and its renderings. Its model and parameters cannot be reassigned once it is made. The regions it finds are what the option writes, and neither ONNX Runtime nor those libraries promise the same output across their versions, so a run under Clean Pixel Data has a method digest for each version of each. A finder other than the text detector describes its own method in the same form: a mapping that is not empty, whose values are text, integers, floating-point numbers, bytes, or UUIDs, in mappings, sequences, and sets. A finder without such a description is refused, as is a boolean ornullin it, as for the parameters of generated values.Runtime software can affect execution. Equality of method digests therefore means equality of the components that the method digest covers; it is not proof of byte-for-byte identical execution or output. Reproducing or auditing an execution also requires its recorded runtime environment and any other relevant external state.
Releases and development builds compute the digest in the same way. An unmodified installation of an official release therefore gives the same method digest for a given policy and set of external resources in every supported runtime environment, apart from a text finder’s runtime under Clean Pixel Data; an edited or repacked installation that claims the release’s version gives another; and two development checkouts that share a
.devversion give different digests when their de-identification source differs. Each release’s conformance statement (Architecture item 10) is to publish the method digest of each enabled preset without a vocabulary, the technique vocabulary, a reviewed-names list, a reviewed descriptors list, or a text finder, and, under Retain Safe Private, with the reviewed safe private rules as its list, naming the PyMedPhys release, the DICOM edition, the preset, and the absence of each, so that anyone can compare a file’s digest with it. A run with a site’s own vocabulary, reviewed-names list, reviewed descriptors list, or other resource has a digest other than that published baseline, as intended, and so does every run under Clean Pixel Data, which needs a text finder, and so does a run under Clean Descriptors with the technique vocabulary, which such a run uses unless it is given none, and so does a run under Retain Safe Private that chooses TCIA’s Private Tag Dictionary as its safe private list. No digest is published yet, since no preset is enabled.De-identifying a file again with the same policy, PyMedPhys files, and resources gives the same method digest under any supported version of Python, pydicom, or tomlkit, so a change of those alone never appears as a new method, whereas a change of the text finder’s runtime under Clean Pixel Data does, as intended, and the later run’s Contributing Equipment Sequence item records its own runtime (D-012). A change to the policy, the rules, the source, the parameters of generated values, or an external resource changes the digest, so the later processing is identifiable as a different method.
A confidential site resource that can change what the engine does contributes to the method digest through a stable keyed digest, never through the resource or an unkeyed digest of it, which anyone could test a guessed resource against. The first is the reviewed-names list of ROI name cleaning (D-009, D-016), which holds source ROI names. Its keyed digest is the HMAC-SHA-256 of the list’s canonical form, its file written without whitespace outside text, with every object’s members sorted, under the run’s key in a derivation domain of its own,
reviewed-roi-names(D-004), so that no UID, patient identifier, or date offset shares its message. The key is never written to DICOM output or reports. The keyed digest is an input to the method digest,reviewed_roi_namesin the serialisation, ornullwithout a list, and is recorded wherever the digest’s components are. The same list under the same key gives the same value in every run, and a change to a decision or a name changes the method digest. The second is the reviewed descriptors list (D-009), whose keyed digest is computed in the same way in the domainreviewed-descriptors, asreviewed_descriptorsin the serialisation. The third is the reviewed region rules of Clean Pixel Data (D-037), which hold manufacturers’ and model names that together can identify a site’s equipment, whose keyed digest is computed in the same way from the rules’ canonical form, sorted by key, in the domainpixel-region-rules, aspixel_region_rulesin the serialisation. Under an ephemeral key, each run’s keyed digest, and so its method digest, differs even for the same list, as intended: without the key, nobody can tell whether two runs used the same list. Resources that are not confidential, such as the TG-263 vocabulary and the technique vocabulary (D-036), keep their unkeyed content digests.Each release report records the method digest with the components it is computed from, as structured fields:
method_digest;method_digest_format;engine_version;table_digests, the content digest of each generated table by file name;l2_rules_digest, the SHA-256 of the canonical bytes of thel2_rulesmember of the serialisation;l3_rules, their absence or, once they exist, the SHA-256 of their member;vocabulary_digest, or the absence of a vocabulary;reviewed_roi_names, the keyed digest of the reviewed-names list, or the absence of a list;reviewed_descriptors, the keyed digest of the reviewed descriptors list, or the absence of a list;technique_vocabulary_digest, the SHA-256 of the technique vocabulary, or the absence of one;text_finder_digest, the SHA-256 of thetext_findermember, or the absence of a finder;pixel_region_rules, the keyed digest of the reviewed region rules, or the absence of rules;safe_private_list,reviewedortciaunder the Retain Safe Private Option, or the absence of a list without it;generated_values_digest, the SHA-256 of thegenerated_valuesmember; andengine_files, the SHA-256 of each source and rule file by its path. These show which component differs between two digests. Like the rest of the report, they contain no key, source identifier, source value, or patient data (D-016).
Rationale. Two runs carry the same digest only if they have the same policy, PyMedPhys version, generated tables, rules, vocabulary, text finder, parameters of generated values, package files, and outside modules, with the files and tables as each run’s process read them at its first digest. The vocabulary and the L3 rules are not generated tables, but they decide what the engine keeps and writes as much as the tables do, and the engine’s version stands for its code in a release. Every call states the vocabulary, or None for its absence, by name: with a default, a caller that forgot the vocabulary would record no vocabulary while descriptor cleaning used one. The digest also changes when an unrelated rule changes, which is harmless. Covering only what the policy uses was rejected: deciding which rules are used would be another dependency calculation that could be wrong, and if it were, behaviour could change silently under the same digest, which is the dangerous failure; a change of digest that proves unnecessary is the safer error. A serialisation that fixes every byte, and states each value’s type where JSON alone would not, encodes the same inputs as the same bytes whatever platform and Python version computes it, which hashing Python’s own representations of the values would not. Development builds and editable installs share a version, such as
0.42.0.dev0, across commits, and an edited or repacked installation can claim a release’s version, so the engine’s files identify their code where the version cannot; limiting the guarantee to released versions was rejected because tests and pilots run such builds, and selecting the files by type, rather than by a list of those that decide behaviour, cannot leave out a new module of the package. Code outside the package decides behaviour too: contour clipping moved topymedphys._geometryso that other parts of PyMedPhys can use it, and ROI name matching is inpymedphys._nomenclature, so a digest of the package alone would let either change what is written under the same digest. Covering every module the package imports, directly or through one another, rather than only those judged to decide behaviour, follows the same reasoning as covering the whole package. The outside modules are listed rather than found when the digest is computed, because finding them would mean resolving imports at run time, another dependency calculation that could be wrong; a test that scans the imports instead keeps the list complete. Covering all of PyMedPhys was rejected, because every unrelated change would then give the method a new identity. Reading the files and tables once per process gives every instance of a run the same digest, even when a file of an editable install is edited after the first digest, which would otherwise give later output of the old code the new files’ digest. Apart from the text finder’s, the runtime environment is left out of the digest for two reasons. The first is comparability: with the versions of Python, pydicom, and tomlkit as inputs, every routine upgrade would give the same method a new identity, so no stable digest could be published for a release, policy, and set of resources, sites could not compare their digests without also matching their environments, and de-identifying a file again after an upgrade would record what looks like a new method. The second is that a few version strings do not identify an execution: it can also depend on how packages were built, on the libraries they load, on details of the platform, and on other external state, so a digest of selected versions would look like a complete fingerprint of behaviour without being one. Recording the runtime as readable provenance shows a custodian what actually ran, which a second, opaque digest in De-identification Method would not, so none is written there, and the effect of the runtime on behaviour is managed by testing the supported environments (D-029). The text finder’s runtime is the exception because what it decides is the regions written, from a network’s floating-point output, which testing a few environments cannot bound. The finder’s class is part of its identity because its description is only what it says of itself: without the class, a wrapper or a subclass that gave the text detector’s description would share the detector’s digest while finding other regions, which is the dangerous failure above. A plain SHA-256 of a small or guessable confidential list could be reversed by hashing candidate lists offline, which a keyed digest prevents, and a derivation domain of its own keeps the resource’s identifier apart from patient pseudonyms, UIDs, and date offsets derived under the same key. The keyed digest, like the vocabulary, must be stated by name with no default, so a caller that forgot the list would be refused rather than record no list while descriptor cleaning used one.Tests. Changing PyMedPhys’s version, any part of the policy, its preset, any generated table, L2 rule, L3 rule, the vocabulary’s entries, any parameter of generated values, or any source or rule file of the engine changes the digest, including one that the selected options do not use, as does adding, removing, or renaming a file, adding or removing a vocabulary, or adding, removing, or changing the reviewed-names list’s keyed digest, the text finder’s description, or the region rules’ keyed digest, each of which shows only in its own component, or choosing TCIA’s Private Tag Dictionary in place of the reviewed rules under the Retain Safe Private Option, which shows in
safe_private_listand is refused without the Option, and a keyed digest that is not 64 lowercase hexadecimal digits, or a call that does not state the list by name, is refused; changing the Python implementation, the Python version, or the version of pydicom or tomlkit, one at a time or all together, leaves the digest unchanged; the serialisation holds exactly the members listed, and while there are no L3 rules, records their absence; the same version, policy, tables, rules, vocabulary, parameters, and files always give the same digest, in whatever order mappings and sets hold them; a small synthetic input gives canonical bytes written out by hand and their independently computed SHA-256, and changing only a value’s type changes them; files with CRLF and LF line endings give the same digest, and caches and files of other types are left out; every file of the package other than caches has a type that the digest covers, so a file of a new type fails the tests until the digest covers it; every file is covered when the package is installed below a directory whose name starts with.; changing, adding, or removing a file of an outside module, such as one ofpymedphys._geometry, changes the digest and shows only in its own file’s digest, the digest is refused when an outside module cannot be found, an edit to one after the first digest is not seen until it is read again, and a scan of the package’s imports finds every outside module listed and no other; the digest is refused when the package’s files cannot be found or do not include the module that computes it; an edit to the files or tables after the first digest is not seen until they are read again, as in a new process; a table whose rows do not match its recorded digest is rejected; a reformatted table keeps its content digest, which is computed from its rows, but changes its file’s digest; a call that does not state the vocabulary by name is refused; a text finder’s class and description are written with each value’s type, a finder of another class with the same description gives another digest, a change to a finder after the transform is made changes neither the markers’ digest nor the report’s, the text detector’s description of its default parameters has a canonical form, and a description that is not a mapping, is empty, or holds a value of another type is refused, as is reassigning the text detector’s model or parameters; and the digest is 64 lowercase hexadecimal digits, so it reveals no value.
D-025: File Meta Information#
Decision.
The File Meta Information that the engine builds (D-002) holds exactly these elements: File Meta Information Group Length (0002,0000), File Meta Information Version (0002,0001), Media Storage SOP Class UID (0002,0002), Media Storage SOP Instance UID (0002,0003), Transfer Syntax UID (0002,0010), Implementation Class UID (0002,0012), and Implementation Version Name (0002,0013).
It names the de-identifier by the fixed Implementation Class UID
1.2.826.0.1.3680043.10.188.1.1, the first UID of the arc1.2.826.0.1.3680043.10.188.1that PyMedPhys reserves for UIDs fixed in its design, under its registered root,1.2.826.0.1.3680043.10.188. The maintainer decided this on 1 October 2026, in place of a2.25.UID derived from a documented name.Implementation Version Name is
PYMEDPHYS, followed by the version where the result fits the 16 characters of SH. A single space separates them, as inPYMEDPHYS 0.42.0, and a development or local version that does not fit, such as0.42.0.dev1, givesPYMEDPHYSalone.Every other element is omitted, whatever the source file held: Source Application Entity Title (0002,0016), Sending Application Entity Title (0002,0017), and Receiving Application Entity Title (0002,0018); Source Presentation Address (0002,0026), Sending Presentation Address (0002,0027), and Receiving Presentation Address (0002,0028); and private File Meta elements, such as Private Information Creator UID (0002,0100) and Private Information (0002,0102).
Rationale. The elements written are the six that PS3.10 Table 7.1-1 makes Type 1, and Implementation Version Name. The table’s other elements are Type 3, except Private Information, which is required only with a Private Information Creator UID, so omitting them keeps the file valid. The titles and addresses of the systems that created, sent, and received the source file can identify the institution, so none is carried into the output. PS3.7 D.3.3.2 requires Implementation Class UIDs to be registered by the implementing organisation per the policies of PS3.5; PS3.5 9.2.2 makes an organisation responsible for registering its UIDs, at least by obtaining a registered root; and PS3.5 B.2, which is informative, advises that a UUID-derived UID is usually not appropriate for an Implementation Class UID. A UID under the registered PyMedPhys root meets all three and leads back to PyMedPhys. Every UID that PyMedPhys generates under the root adds at most one component after it, so none falls under the reserved arc, whose reservation is recorded beside the root in
pymedphys._dicom.uid. A version that does not fit beside the name is left out rather than shortened, because a shortened version would name another release. PS3.7 D.3.3.2 requires, where there is no Implementation Version Name, that one Implementation Class UID means one version of the implementation, and notes that a version name is expected to include version information;PYMEDPHYSalone is therefore still written, since the UID stays the same across versions, and the full version is always in Software Versions (0018,1020) of the Contributing Equipment item (D-012).Tests. Every output file’s File Meta Information holds exactly the seven elements listed, with the fixed Implementation Class UID
1.2.826.0.1.3680043.10.188.1.1and an Implementation Version Name ofPYMEDPHYSwith the version where it fits 16 characters; and no output file carries an Application Entity Title, a Presentation Address, or a private element in its File Meta Information, whatever the source file’s File Meta Information held.
D-026: Reference graph findings#
Decision. The first pass’s findings (Architecture item 8) have graded consequences:
A dangling reference is reported only: the release report counts the instances with each kind of finding reported only, and the confidential QC pack lists each such finding at each instance it names, with the attribute’s tags and its count.
A frame of reference mismatch is reported only, and its instances are still written. The maintainer decided this on 6 October 2026. The mismatches are a series whose instances name several frames of reference, an RT Structure Set ROI whose frame of reference the structure set does not list once and only once, and an image that a structure set lists under another frame of reference than its own (Architecture item 8).
Identical duplicate instances are written once. The maintainer decided on 1 October 2026 that instances that share a SOP Instance UID are identical only when their source bytes are the same: the same Transfer Syntax UID, and the same bytes of the data set after the File Meta Information, ignoring the preamble, the File Meta Information, and the top-level group lengths (gggg,0000) and Data Set Trailing Padding (FFFC,FFFC) (Architecture item 8).
Instances that share a SOP Instance UID with different source bytes, or whose bytes the first pass cannot show to be sound, are all sequestered.
A series whose instances name several studies is sequestered.
A study whose instances name several patients stops the run before anything is written, unless the run is told to sequester such a study. The maintainer decided on 1 October 2026 that a patient is a Patient ID with its Issuer of Patient ID (0010,0021), the identity from which D-005 derives pseudonyms, so a study in which a planning system has dropped the issuer from some instances stops the run. An instance without a Patient ID counts as a patient apart from every identity, which is the conservative reading of that decision: the instances without one together form one patient, so a study that mixes instances with and without a Patient ID stops the run, and a study whose instances all lack one does not. The maintainer decided on 10 October 2026 to keep stopping the run by default, and to record as an option, should such studies become a problem in practice, a command-line opt-in that sequesters the study, reports it, and lets the rest of the run go ahead, still collecting the sequestered study’s values and searching for them in the files of every patient that the study names. On 31 October 2026 he decided to build that opt-in now:
The run command’s and the pilot command’s
--sequester-studies-with-several-patients, the library API’ssequester_studies_with_several_patients=True, and the run’sSeveralPatients.SEQUESTERsequester every instance of each such study, with the reasonstudy-with-several-patientsof thereferencesstage, and the rest of the run goes ahead. Without it the run stops, as before. A study is sequestered whole, since the first pass cannot tell which patient’s instances are the strays.Each instance of the study is still transformed, as is every instance that a first-pass finding sequesters, and never written. It is not among the records from which the transform prepares what needs several instances at once, so the study takes no part in a subject’s synthetic birth date (D-008) or in a CT series’ face block (D-050). Its evidence joins the pooled collection of every patient that the study names, the instances without a Patient ID being one such patient, so each released file of each of them is searched for every value of the study, and a value of the study that could not be collected, or an instance of it that changed during the run, withholds those files as it would its own subject’s (D-027). A reference from a released instance to an instance of the study is reported only, as one to any withheld instance is.
The release report’s
studies_with_several_patientssection gives the run’s choice and how many studies it sequestered, and the QC pack’sseveral_patient_studiesgives each by the run positions of its instances, grouped by patient as the first pass grouped them, for a curator to correct; neither names a study or a patient. The choice is the run’s, not the policy’s: it changes nothing in a released instance, so the method digest (D-024) and the conformance statement do not record it.Caveats, which the user documentation states: the release lacks every instance of the study, including those of the patient that most of it names, so the record of each patient that it names is incomplete in the release; a released file of a patient that the study names is withheld where it holds a value of the study, such as a kept equipment name that holds a component of the other patient’s name, even where that is a coincidence; the run corrects nothing, so the curator corrects the source, such as by restoring the Issuer of Patient ID or the right Patient ID, from the instances that the QC pack groups; under a run-scoped key, which the first supported release uses, the key is made for the run and then discarded (D-004), so the corrected study cannot be added to that release later, only released again with the rest of its cohort by a new run that replaces it; and under a project key, once project keys are enabled, a later run can add the corrected study with the pseudonyms, UIDs, and date offsets of the earlier release, but its Series Numbers are ranked within that run alone (D-022), and under
tps-importthe subject’s synthetic birth date was chosen without the study, so a corrected study that contradicts the reference study that the subject’s profile records stops the subject for review (D-008).
An instance without its SOP Instance UID, Series Instance UID, or Study Instance UID is sequestered: it cannot be named (D-016), and the first pass cannot check it against its series and study.
Release reports name instances by their output names only. Run positions and source paths appear only in the confidential QC pack (D-016).
A sequestered instance has no output name. The maintainer decided on 2 October 2026 that release reports name each one by an opaque label for the run, such as
S-0007, with its reasons, and that only the confidential QC pack maps labels to sources. Labels are assigned in an order drawn at random, so a label says nothing of the instance or its place in the run.
Rationale. Real exports routinely contain dangling references, such as a plan that references a dose that was not exported, so stopping on every finding would make the engine unusable, and reporting every finding without acting on it could release inconsistent collections. A study with several patients is a curation error that no action on individual instances can repair safely. Where such studies are common, as where an export mixes patients by mistake, stopping every run withholds the sound studies with the faulty one, so the opt-in sequesters the whole study instead, failing safe, and searches each patient that it names for its values, since a stray instance can carry one patient’s identifiers into the files of another. An empty Patient ID needs a curated identity (D-005), and an unresolved identity stops its instances for curator resolution (D-008); a curated identity would give such an instance a different pseudonym from the rest of its study, the outcome that stopping a study with several patients exists to prevent. Comparing source bytes needs no decoder and no resolution of VRs, so no behaviour of pydicom, such as guessing the VR of an element that an Implicit VR file holds without one, can make different values compare equal, and comparing copies cannot change the data set that a caller holds. The same bytes can be different values in different encodings,
ff ffbeing -1 as SS and 65535 as US, and01 00being 1 in a little endian OW value and 256 in a big endian one, so the transfer syntax, which decides the encoding of the bytes, is part of the comparison. Writing one of two copies that differ would silently drop the other’s content, while sequestering both loses nothing that a curator cannot recover. So the cost of comparing bytes, that copies that differ only in their encoding are sequestered for a curator, loses nothing, and a copy whose bytes cannot be shown to be sound counts as a conflict, which fails safe. A frame of reference mismatch is a matter of the data’s integrity, not of disclosure: replacing every UID consistently neither creates nor hides one, and contours drawn on an image registered to the planning CT legitimately sit in another frame of reference, so withholding for it would block sound collections.Tests. A dangling reference is reported and its instance still written; copies with another preamble or File Meta Information, with top-level group lengths, or with top-level Data Set Trailing Padding are identical; the digest is the SHA-256 of the Transfer Syntax UID and the data set’s bytes, computed by hand from the file; copies of one data set in Implicit VR and in Explicit VR Little Endian conflict, with or without a private element, as do copies with sequences of defined and of undefined length, with more padding of a value, with a group length or Data Set Trailing Padding inside an item, and with the same data set bytes under another transfer syntax; any changed value or VR, added or removed element, or changed private element makes copies conflict, as do a private element written as SS -1 in one copy and as US 65535 in the other, the same OW bytes in little and big endian, a private or unlisted element read as UN in one copy and with a VR in the other, compressed and uncompressed Pixel Data, and 8-bit Pixel Data in Implicit VR and in Explicit VR; a file in a deflated transfer syntax, without a Transfer Syntax UID, followed by bytes that cannot be read, or with a top-level group length or Data Set Trailing Padding that holds items has no digest, and conflicts with every other copy, even another copy of the same file, while one in Explicit VR Big Endian or truncated within a sequence that the first pass follows, or with such a sequence of Explicit VR, of Implicit VR, or of VR UN whose items run past it, at the top level or nested, has no record; the same Patient ID from another issuer, or without one, is another patient, a study that mixes instances with and without a Patient ID has several patients, and a study whose instances all lack one has one; with the opt-in, every instance of each such study is sequestered, identical copies within it too, and the rest of the run released, a choice that is not a
SeveralPatientsis refused before anything is created, the study’s instances are transformed but not prepared from, their evidence reaches the gate of every released file of each patient that the study names and of no other patient, an instance of the study that changes during the run withholds the files of every patient it names, a named patient’s file whose kept text holds a component of another named patient’s name is withheld while a patient that the study does not name keeps the same text, the release report gives the choice and the count of studies,stopwith none andsequesterwith any number, refusing a count understop, and the QC pack gives each study’s instances by patient, refusing an instance that was not sequestered or is in two studies; identical duplicates give one output file; every instance that shares a SOP Instance UID with different source bytes is sequestered; a series that names several studies is sequestered; a study that names several patients stops the run with nothing written, by default and when told so explicitly; release reports name instances by their output names, never by run positions or source paths; they name sequestered instances by labels that carry nothing of the instance or the run’s order, with reasons that hold only codes and tags; and an instance without its SOP Instance, Series Instance, or Study Instance UID is sequestered; and a series in several frames of reference, an ROI whose frame of reference is not listed once, and a contour image in another frame of reference are each reported, and their instances still written.
D-027: Residual search#
Decision. The search of each output file after writing (Architecture item 8) is strict:
Any residual person name, UID, or date, and any finding outside the data set, in the preamble, the File Meta Information, or trailing bytes, fails the file, and its instance is sequestered.
A residual direct identifier fails the file in the same way, although the search reports it as text. A direct identifier is an attribute that Table E.1-1 lists in a PS3.6 group of the patient, a visit, the study, or a procedure or order (0008, 0010, 0020, 0032, 0038, or 0040), or that is Clinical Trial Subject ID (0012,0040) or Clinical Trial Subject Reading ID (0012,0042), that is neither a sequence nor a UID, that no option retains or cleans, and whose keyword has
ID,IDs,Number,Numbers, orLocatoras a word, such asPatientIDorPlacerOrderNumberImagingServiceRequest; it counts wherever it occurs, as in the items of Other Patient IDs Sequence (0010,1002). In 2026d this selects 24 attributes, 17 of them current: Patient ID (0010,0020), Issuer of Patient ID (0010,0021), Patient’s Telephone Numbers (0010,2154), Accession Number (0008,0050), Referring Physician’s Telephone Numbers (0008,0094), Study ID (0020,0010), Admission ID (0038,0010), Service Episode ID (0038,0060), Scheduled Procedure Step ID (0040,0009), Performed Procedure Step ID (0040,0253), Requested Procedure ID (0040,1001), Person’s Telephone Numbers (0040,1103), Order Callback Phone Number (0040,2010), Placer Order Number / Imaging Service Request (0040,2016), Filler Order Number / Imaging Service Request (0040,2017), Clinical Trial Subject ID (0012,0040), and Clinical Trial Subject Reading ID (0012,0042), and the retired Other Patient IDs (0010,1000), Medical Record Locator (0010,1090), Study ID Issuer (0032,0012), Issuer of Admission ID (0038,0011), Issuer of Service Episode ID (0038,0061), Specimen Accession Number (0040,050A), and Telephone Number (Trial) (0040,A354). The maintainer decided on 25 October 2026 that the two clinical trial subject IDs are direct identifiers, named by tag, and that the other clinical trial identifiers of group 0012 are not.Text findings inside the data set go to confidential QC review (D-016), apart from those that kept standard vocabulary or an equipment name explains, or whose source is a standard code’s meaning that only instances the run does not write held (D-032), or that a value a selected option keeps explains (D-042).
As the maintainer decided on 2 October 2026, transforming a value and collecting it for the search are separate, and release is conditional on both. The release gate enforces exactly this:
Coverage. The walker reports the paths of the values it planned to collect, those it collected, those it could not collect, with a reason that holds no value, and those it read only as bytes. Collection is complete only when every planned value was collected from its decoded form under a VR that the pinned dictionary gives its attribute. It is incomplete where a planned value was neither collected nor reported as not collected, so an empty collection is never taken as complete; where a value could not be collected; where text outside ISO 646 with no Specific Character Set was read only as ISO 8859-1 (Architecture item 5), since searching its bytes supplements the coverage but does not stand in for the decoded text, whose copies in other attributes or encodings were not searched for; and where a value was collected under another VR, such as a person name collected as CS, which the search would leave out or search in the wrong forms. Coverage is pooled across the subject, as the values searched for are, so a sibling instance’s gap counts against every file of the subject, even where another instance collected a value at the same path. An instance out of scope whose IOD the pinned tables define, such as an ultrasound image, is read, planned, and edited only so that its values are collected for its subject’s search, and is never written, so that it withholds its subject’s files only where its collection is incomplete, as any instance’s would. Under Clean Descriptors, such an instance, like any other withheld before its descriptors are cleaned, leaves out of that collection the descriptors that cleaning would write with a kept value (D-009). This is “Collect first”, which builds on “Withhold”, as the maintainer decided on 6 October 2026. An instance of the subject whose values were not collected at all, because its source was refused, its SOP Class names no IOD of the pinned tables, its Specific Character Set cannot be decoded, its transform failed, or it changed during the run, withholds every file of the subject, since its values could be in them unsearched for; and where the walker sequesters an instance, the planned values it did not reach are not collected, rather than not reported. Values in an instance whose file could not be read as DICOM, which names no subject, are not pooled. File Meta Information and preamble values are not collected; the writer rewrites both, so neither is released, but a copy of one in kept text is not searched for.
Search. The gate runs the search itself, for exactly the pooled collected values, so no other search can stand in for it. The forms that the search leaves out by the rules below, such as those shorter than four characters and binary values, are its exclusions: they are listed with their reasons and never count as incomplete.
Withheld. A file is withheld where collection is incomplete for an attribute to which the pinned dictionary gives VR PN, UI, DA, DT, or SQ, whose items’ content is unknown, or for a direct identifier; where its structure cannot be read to its end; and where the search finds a person name, UID, date, datetime, or direct identifier anywhere, other than a person name found inside the data set in standard text that a selected option keeps, which goes to QC review, a date or datetime equal to a whole date or time that a selected option keeps, a datetime whose date equals a whole date that a selected option keeps, or a date, or a datetime’s date, that is the date that begins a whole datetime that a selected option keeps, or a UID equal to a whole UID that a selected option keeps where only instances that the run does not write held it, or where its source is a private data element that every instance which held it removed (D-042), or any value in the preamble, the File Meta Information, Data Set Trailing Padding, which holds no value, or bytes after the data set. Kinds are taken from the VR that the pinned dictionary gives the source attribute, whatever VR the value was collected under, and from the search only where the dictionary gives none.
QC review. A file goes to QC review where collection is incomplete for any other value, including a private value or one to which the dictionary gives no VR; where the search finds a person name inside the data set in an attribute that a selected option keeps and that the pinned dictionary gives only VRs of text, which nothing explains (D-042); or where it finds other text inside the data set that D-032 or D-042 does not exempt. Binary values are outside the search’s contract, which leaves them out, and a private value that could not be collected is outside its reach, although decoded private text is searched like any other text; withholding every file with a vendor’s private value that could not be collected would sequester nearly every RT file, so the residual risk is listed in the QC pack instead.
Released otherwise. A search that finds nothing is not on its own a release. The gate takes the most severe consequence of every reason, each named by an attribute path and a reason code, never a value, and has no setting that relaxes it. Release reports are to count the reasons by attribute and code, and the QC pack to list them in full (D-016, D-026).
Clarification of the decisions of 1 October 2026 on content that cannot be decoded, 2 October 2026. Where those decisions say that “the instance is de-identified” (D-010) and that values that cannot be decoded “are listed as not searched”, the transformation proceeds and the values are listed as not collected; release remains conditional on the required coverage. For example:
Source
Before the clarification
After it
Patient’s Name removed, with bytes outside ISO 646 and no Specific Character Set
Read as ISO 8859-1, searched, and released after a clean search
Withheld: incomplete collection of a person name
Study Description removed, with the same bytes
Released after a clean search
QC review: incomplete collection of other text
Study Description kept or cleaned, with the same bytes
Instance sequestered
Instance sequestered, as before
The maintainer decided on 2 October 2026 that release reports count the drops and the values not searched by attribute and reason, and that the confidential QC pack lists each one by instance and place (D-016).
As the maintainer decided on 6 October 2026, a residual person name found inside a retained label, such as a beam name, ROI name, or plan label, still withholds the file in the first supported release, even where it is also an ordinary word, as a surname can be in a beam name (
FIELD^MARGARETagainst a Beam Name ofField 1). Before that changes, for example to send such findings to QC review, their effect is first measured with a list of surnames.Values that the policy legitimately retains are dropped from the search, and each drop is recorded. A drop skips only the retained copy, by its place, and never the value: the same value that the policy removes or replaces in another attribute is still collected, pooled across the subject, and searched for, so it is found in the retained copy. A person name removed from Patient’s Name and found in a retained Beam Name therefore withholds the file, as decided on 6 October 2026, and only D-032 and D-042 exempt a finding that kept vocabulary or a value that a selected option keeps explains.
Values that hold numbers are searched only for forms of at least 8 bytes that are not UTF-16LE, and entropy-coded data only for forms of at least 6 bytes (Architecture item 8). These rules apply to whole regions of a written file, not to particular values, so the search does not list them for each value, and release reports do not state them: the conformance statement states both, with the lengths that the search itself uses, alongside what the search lists as not searched.
Values shorter than 4 characters are not searched, and are listed as not searched. Binary values, values of VR AS, AT, CS, DS, FD, FL, IS, SL, SS, SV, TM, UL, US, and UV, and datetimes without a full date are also listed as not searched, and are checked attribute by attribute instead (Architecture item 8).
Content that cannot be decoded inside a sequence that is removed is removed with it, and its values are listed as not searched in the confidential QC material (D-016). An instance is sequestered only where content that cannot be decoded would be kept or cleaned (Architecture item 2). The maintainer decided this on 1 October 2026.
A source value that exactly equals a constant that the engine always writes, such as a dummy date or
DEIDENTIFIED, is not searched, and each such skip is recorded by its source attribute, never by its value. The maintainer decided this on 1 October 2026.The constants for that skip are D’s first and second constants, the values of D’s item in Person Identification Code Sequence, and the markers’ fixed values, of which the option codes are only those of the options that the engine applies, since it refuses any other and so never writes its code, and not the keyed pseudonyms or the markers’ versions and method digest; a source value equals one when D would treat it as equal to its constant (Architecture item 8). The maintainer decided this on 5 October 2026.
A form of a source value that equals such a constant is skipped in the same way, and the value’s other forms are still searched. So the family name of a person name
DEIDENTIFIED^ABCDEFfrom data that was de-identified before, which is the family name of every keyed pseudonym, is not searched, and nor are the words of a family nameDE-IDENTIFIED, butABCDEFis; and the date of a datetime19000101120000, written as YYYYMMDD, is not searched, but the whole datetime and the date’s other spellings are. The maintainer decided this on 5 October 2026.Output is written to a staging area and moved to the release directory only after a clean search. The staging area is a directory beside the release directory, named for it, so on its file system, and created for the run with permissions for its owner alone where the platform has them, since it holds output that may still identify people, as QC material does (D-016). Each file is written there under a temporary name and renamed once its bytes are on disk, read back for the search, and deleted at once if it is not released. A file held for review is deleted too, and is written again by a run after its review, whose release replaces the earlier one, since the current command gives each run an ephemeral key (D-004); the maintainer decided this on 6 October 2026, for a file held for ROI name review (D-009) and for one held for a text finding of the search alike. The release directory must not exist before the run, and is published by one rename of the staged tree, so it appears whole, with only files that passed, or not at all. A run that fails deletes its staging area; one that a crash leaves holds output that may still identify people, so a run refuses to start beside it until someone has reviewed and deleted it.
Rationale. Nothing leaks silently, at the cost of some false positives that need human review. Reporting findings only was rejected because the search would become advisory. Failing a file on any match was rejected because legitimate overlaps would make the engine unusable: a removed Study Description that reads
CHESTis found inside a retained Body Part Examined that readsCHESTABDOMEN, and review, not failure, settles it. A direct identifier identifies the patient, a visit, or the study on its own, as a name does, so it fails the file although the search reports it as text. Each clinical trial subject ID names one subject, and the trial site holds the key that links it to the patient, so it is a direct identifier as a Patient ID is; the protocol, site, series, and time point IDs of group 0012 are defined for the trial, a site, a series, or a group of studies rather than for a subject, although a trial may assign a series or time point ID to one subject alone, so the chosen policy keeps them under the QC review that other residual text receives, where a reviewer judges each finding, rather than withholding every file in which one is found. Naming the two by tag costs yield only where a removed subject ID survives in kept text, whose file is then withheld rather than held for review. Selecting direct identifiers from the pinned tables by a rule, rather than keeping a list by hand, covers those that a new edition adds, and leaving out those that an option retains or cleans, such as device identifiers, keeps to attributes that every option removes or replaces. A constant that the engine always writes is in the output whatever the source held, so finding it reveals nothing about the source and would fail every file whose source happened to hold it; recording the skip by attribute keeps it visible without repeating the value. Content that cannot be decoded cannot be matched, cleaned, or searched. Removing it with a sequence that is removed anyway loses nothing the output keeps, listing its values keeps the gap visible to reviewers, and sequestering an instance that would keep or clean such content means that nothing unchecked is written.Tests. A residual person name, UID, date, or datetime, and any residual in the preamble, File Meta Information, Data Set Trailing Padding, or trailing bytes, sequesters the instance and leaves nothing in the release directory; incomplete collection of a person name, UID, date, datetime, direct identifier, or unread sequence withholds the file after a search that finds nothing, including where a planned value was neither collected nor reported, where the gap is a sibling instance’s, and where a person name was collected as CS, OB, or LO, while incomplete collection of other text, of a private value, or of an attribute without a VR in the dictionary goes to QC review; the clarification’s examples give the outcomes in its table; the search covers the pooled values; the search’s exclusions are listed and leave collection complete; a file whose structure cannot be read to its end is withheld; the most severe reason decides, in either order; reasons and reprs hold no value; a residual of each direct identifier that the rule selects from the pinned tables, such as Patient ID in an item of Other Patient IDs Sequence or Accession Number in a private element, does the same, and the rule selects exactly the attributes listed above; a residual or uncollected clinical trial subject ID withholds the file, while a residual or uncollected protocol, site, series, or time point ID goes to QC review; a text finding inside the data set reaches QC review; retained values are dropped from the search, and each drop is recorded, counted in the release report by attribute and reason; before the pipeline drops retained values, a regression case shows that a legitimately retained occurrence of a value cannot conceal the same source string in the preamble or trailing bytes; values shorter than 4 characters are listed as not searched; a source value that exactly equals a constant the engine always writes is skipped and recorded by its source attribute, never by its value, while one that differs from it is still searched, as is a Patient ID equal to the code or meaning of an option that the engine refuses; a form of a value that equals such a constant, such as the family name of an earlier pseudonym, is skipped and recorded in the same way, while the value’s other forms are still found; content that cannot be decoded inside a removed sequence is removed and its values are listed as not collected in the confidential QC material, and an instance that would keep or clean such content is sequestered; nothing reaches the release directory before its search is clean; the release directory appears whole or not at all; and a staging area that an interrupted run leaves stops the next run beside it.
D-028: Private attributes without Retain Safe Private#
Decision.
Without the Retain Safe Private Option, every element of an odd group is removed, since Table E.1-1 gives Private Attributes, “(gggg,eeee) where gggg is odd”, X: each private data element, whether or not its block has a private creator; each private creator, including one that reserves a block with no elements; and each element that PS3.5 Section 7.8.1 does not allow, in groups 0001, 0003, 0005, 0007, and FFFF or at (gggg,0001) to (gggg,000F) and (gggg,0100) to (gggg,0FFF), and each retired group length, (gggg,0000).
They are removed at the top level and in the items of every standard sequence, as E.1.1 requires for every attribute of the table. The engine’s rules give each element of a private group the Private Attributes row’s X, remove an element of a group that PS3.5 does not allow for private use as an attribute that the pinned data dictionary does not list, and remove each group length; the walker plans every element of the source by its rule. A private sequence is removed with its items and everything in them, as X requires (Table E.1-1a): the walker plans each element in them as removed with it, without a rule of its own, and their values are still collected for the residual search (D-027).
The engine finds them in the source file’s bytes, which it reads independently of pydicom (Architecture item 2). A value written as UN, or without a VR in Implicit VR Little Endian, of an attribute to which the pinned data dictionary gives VR SQ is read as Implicit VR Little Endian items, as PS3.5 Section 6.2.2 allows, at every depth, whether or not pydicom’s dictionary knows the attribute, so the private attributes in the items of a sequence such as RT Assertions Sequence (0044,0110), which pydicom 3.0.2 reads as UN, are found and removed. A source file in which such a value does not hold only items is refused, wherever the value is, even in a sequence that a rule removes, since the private attributes that its bytes may hold cannot be found. A value written as UN whose attribute the dictionary gives another VR holds no items, and one whose attribute the dictionary does not list is removed by its rule. The writer copies a kept sequence’s bytes where nothing in it changes, and otherwise writes it again from its items (Architecture item 2).
A kept standard sequence that Explicit VR Little Endian stores with a VR that the dictionary does not give it, such as OB, sequesters its instance, since its items cannot be read; one that a rule removes is removed whole.
Removing an element reads no value, so a Specific Character Set (0008,0005), at the top level or in an item, does not decide which private attributes are removed; it decides how the values that are kept or cleaned, and the removed values that the residual search collects, are read (D-010, D-027). Where the instance transform cannot read a top-level Specific Character Set, such as one stored with a VR other than CS, the instance’s scope is still decided first, from its SOP Class UID, which as UI no character set changes: an instance whose SOP Class names no IOD of the pinned tables gives its scope reason alone, and any other gives the character set’s reason after any scope reason. A value that the transform reads but does not support gives the Default Character Repertoire instead (D-010).
Elements are found by their tags in the source’s layout, and named by their paths. Planning their removal reads no value, and the plan and its reasons name tags, paths, actions, and VRs, never a value.
A policy that gives Private Attributes another action than X without Retain Safe Private, or than C with it, is refused before any element is planned. Under that option, the reviewed rules settle the C that the table gives them (D-035).
Private Data Element Characteristics Sequence (0008,0300) describes an instance’s private blocks, and D-022 keeps Private Creator Reference (0008,0302) in its items, so the private creator of each block that this decision removes would survive there after every block that it describes has gone. The maintainer decided on 6 October 2026 that the sequence is removed whenever no private attribute is kept. Under Retain Safe Private it is read to find the private attributes that the instance declares safe, and then removed too, since its descriptions and the creators of blocks that are not kept can name the institution’s software (D-035), so a supplementary rule gives it X/Z/D under every policy, which removes it at its Type 3 place in the SOP Common Module.
Rationale.
PS3.5 Section 7.8.1 lets a de-identifier keep or remove a private creator whose block is removed. Removing every one follows the table, which names Private Attributes by their group alone, and E.3.10, which keeps only “the Private Creator IDs that are required to fully define the retained Private Attributes”. A private creator can name the institution, as D-022 notes for in-house software. Keeping private creators was rejected because, without their blocks, they carry nothing useful, and no rule reviews their values.
The elements that PS3.5 does not allow have no defined content, so nothing shows that keeping them is safe, and the table’s X covers them by their group.
pydicom 3.0.2 does not know some sequences of the first supported release’s IODs, such as RT Assertions Sequence (0044,0110) and Dose Calculation Model Sequence (3004,0080), and E.1.1 requires a private attribute in their items to be removed too. Sequestering every instance with such a sequence that holds a private attribute was rejected, because Architecture item 2 already reads a value written as UN, or without a VR, by its attribute’s dictionary VR. pydicom decodes some malformed values without an error, as items that leave out part of the value, and those bytes could hold a private attribute that no reading finds, so a source with such a value is refused as a structure that cannot be read, as the engine admits only sources whose whole structure it reads (Architecture item 2), even where a rule would remove the sequence that holds it.
Reading a value written as UN as items only where the dictionary gives its attribute VR SQ leaves every other value as it was written. Only a sequence can hold private attributes, and reading another value as items could find elements in bytes that are not elements, while decoding it with its attribute’s VR could raise an error or a warning that quotes it, as pydicom does for a value of VR US of the wrong length and for an invalid UID, which D-016 forbids.
Removal reads no text, so refusing an instance for the character set of a data set or item that holds a private attribute, when nothing in it that is kept or cleaned needs that character set, would sequester it for something that does not reach its output; D-010 and D-027 decide where reading text needs it.
E.3.10 retains the private attributes “known by the de-identifier to be safe”, and Architecture item 6 records the basis for retaining each. Applying the option by removing every private attribute was rejected: the output would claim an option whose purpose, such as keeping the SUV factors of Table E.3.10-1, it does not serve. Refusing it left the option’s rules to a later change, which examines private sequences as E.3.10 requires without changing removal under the Basic Profile (D-035).
Tests. Every element of an odd group is removed, at the top level and in standard sequences at every depth, including private creators with and without elements, private data elements without a creator, each kind of element that PS3.5 does not allow, and retired group lengths, from files in Implicit and Explicit VR Little Endian with private sequences of defined and undefined length, and the plan removes each by its own rule, in the data set’s order; a private sequence is removed with everything in it, each element planned as removed with it; the standard attributes around them are kept; private attributes are removed from the items of a sequence that pydicom reads as UN, in either transfer syntax, and of a known sequence that Explicit VR Little Endian carries as UN, in its items and in sequences nested in them at depth 1 or 2, with items and sequences of defined or undefined length; a source in which a sequence written as UN does not hold only items, kept or inside a sequence that a rule removes, is refused; an item’s Specific Character Set that is not supported does not stop removal; a kept standard sequence stored as OB sequesters its instance; each preset removes private attributes unless it retains safe ones; and a policy that gives Private Attributes another action than its option gives is refused.
D-029: Runtime environments#
Decision.
Each run records its runtime environment as provenance, apart from the method digest (D-024): in Software Versions of its Contributing Equipment Sequence item (D-012), and in a runtime section of its release report, which holds the same values as structured fields rather than one display string:
pymedphys_version,python_implementation,python_version,pydicom_version, andtomlkit_version. The section contains no key, path, or source value (D-016).An execution fingerprint, such as the SHA-256 of a canonical form of the method digest and the runtime section under a format label of its own, may later be added to the release report alone, once something needs it. None is planned, and none is written to DICOM output.
PyMedPhys keeps declaring its dependencies as ranges, such as
pydicom>=3.0.2(D-002), so that it installs as an ordinary library. It does not pin them exactly to keep the method digest stable, since the runtime environment is not part of the method, apart from the text finder’s runtime under Clean Pixel Data (D-024).The tested environment is what continuous integration runs. The de-identification tests are unit tests, which run with the versions of pydicom, tomlkit, and every other dependency that
uv.locklocks: on Python 3.12, 3.13, and 3.14, on Ubuntu, Windows, and macOS, in the full matrix that pushes tomain, releases, and pull requests labelledfull-testrun; on Python 3.14 on Ubuntu for merge groups and other pull requests; on Python 3.14 on Ubuntu with only thedicomextra installed; and on Python 3.12 with the declared minimum versions of NumPy and pandas. Wherever the unit tests run, which includes every pull request that changes the de-identification package, its tests,pyproject.toml, oruv.lock, and every release before it is published, the de-identification tests (thetest_deidentify_*modules intests/dicomand the table generator’s tests intests/dev/test_deid_tables.py) also have coverage on Python 3.14 on Ubuntu, with every other dependency at its locked version: with pydicom 3.0.2, the lowest release that the declared minimum allows, and with the latest release of pydicom, which continuous integration resolves from the package index each time, as the workflow guide describes. A minimum or latest version identical to the locked version reuses the normal Ubuntu/Python 3.14 run when that cell runs the complete selection without extra pytest arguments and the lock identifies one registry version. Its imported-version metadata and JUnit report must be present, both compatibility jobs record their evidence references, and the whole unit-test workflow must succeed. Other requested versions run the complete de-identification selection separately; if both roles request the same version distinct from locked, both run. A release of pydicom known to change behaviour that the engine depends on joins these runs, and another dependency is tested at other versions only where its behaviour can plausibly change the output. No other version of pydicom or tomlkit is tested, so releases of pydicom between the minimum and the latest, and releases of tomlkit other than the locked one, are supported by declaration, not by test.
Deferred.
Warn, in a run’s output and its release report, when the run uses a version of Python, pydicom, or tomlkit outside the tested environment, and refuse to run only in an environment known to be incompatible or in an explicit strict or validated mode.
Publish with each release a constraints file of the exact versions that continuous integration tested, so that a deployment of the command line that must be reproducible or validated can install exactly those versions, while library users keep the declared ranges.
Rationale. Runtime software can change what the engine sees: pydicom’s data dictionary decides whether an attribute in an Implicit VR file is read as typed values or, when the dictionary does not know it, as UN bytes, which date shifting, VR checks, and text cleaning then treat differently. That risk is managed by testing the supported environments and recording the one that ran, not by the method’s identity, which would otherwise change with every upgrade (D-024). The declared minimum and the latest release are the oldest and newest versions of pydicom that an installation can resolve, and the latest is what a new installation gets unless another package constrains it, so these runs test what a new installation uses as well as what
uv.lockpins, and resolving the latest each time tests a new pydicom release beforeuv.lockadopts it. Separate, readable fields let a custodian see what ran. Pinning the library’s dependencies exactly would make PyMedPhys hard to install beside other packages, for every user, to serve the deployments that need an exact environment, which a constraints file serves instead.Tests. The release report’s runtime section has each field, with the values that Software Versions records; and continuous integration runs the de-identification tests in the environments listed.
D-030: Independent conformance validation#
Decision.
Check the output’s conformance with validators that share nothing with the engine:
dciodvfyanddcentvfyfrom dicom3tools (BSD-3-Clause), and dicom-validator (MIT), pinned in thetestsextra and reading the DocBook source of the edition that the engine’s tables are generated from (D-001). None is installed for users.Validate each released instance’s input as well as its output, and charge to the de-identification only what the output gives more often than its input. Each introduced finding is explained by an entry of a reviewed file of known differences, whose category is
profile,validator, orengine, and which names any property of the output that its explanation rests on, which the comparison then checks; is not comparable, where the validator could not read the attribute that holds it in the input; or is unexplained, which fails the comparison. Anengineentry records a defect of the output until it is fixed.Keep validator output to tags, message types, and the validators’ module and entity names. A message’s text before its first value, and the reason after it, are kept only where they are made of strings compiled into the validator, and a module, entity, keyword, or IOD name only where the validator holds it, since a value can span lines; any other message or line is counted without its text, so the results hold no value or path (D-016).
Run the comparison in continuous integration over the synthetic corpus, under each preset, on every pull request that runs the unit tests, and offer the same comparison as a development command for any release with a SOP Instance UID mapping, such as the MIDI benchmark’s (D-018). The validation guide describes both.
Rationale. The engine’s own check against the IOD before release (D-020) shares the engine’s reading of PS3.3, so a misreading would pass both; independent validators do not share it. Validators also report what the input already lacks, and the synthetic corpus’s own inputs give thousands of findings, so an absolute verdict on the output would charge the engine with its input’s defects; the difference does not. Pinning the edition makes dicom-validator check the same standard as the tables, and Ubuntu’s dicom3tools package is pinned so that a new snapshot cannot change the results unannounced, at the cost that its dictionary lags the standard, so that
dciodvfychecks nothing of a SOP Class that it does not know, such as Extensible SR, which is counted as unsupported and left out ofdcentvfy’s comparison, as dicom-validator counts a SOP Class it does not know; the job reports the newest snapshot so that the lag stays visible. Rejected: requiring the output to pass outright, which such inputs would fail, and reporting the validators’ messages as they print them, which quotes values.Tests. Unit tests reduce validator output to findings without values and compare findings; and continuous integration runs the validators over the synthetic corpus under each preset, with the validators required.
D-031: Answer-key checks that released files fail by design#
Decision. Of the checks of a MIDI-B answer key on the instances that a run releases (D-018), these fail by design, and are not engine findings:
Longitudinal Temporal Information Modified (0028,0303), which a run sets to
REMOVED, as PS3.15 E.2 requires where no Retain Longitudinal Temporal Information Option is applied (D-012). The key’stext_retainedcheck of it, scored under its TCIA review category, expects another value, so every instance thatbasicorbasic-clean-descriptorsreleases and the key checks there fails it.A
tag_retainedortext_notnullcheck of an attribute that the instance’s IOD requires, such as KVP (0018,0060), Acquisition Number (0020,0012), Position Reference Indicator (0020,1040), or Image Type (0008,0008), where the source lacks the attribute or its value. The engine keeps the first two and Image Type as numbers and codes (D-022), and empties Position Reference Indicator where it is Type 2 (X/Z/D); and it sequesters any instance that it would write without a Type 1 or 2 attribute that its source held, or with a Type 1 attribute emptied (D-020). So a released instance fails such a check only where its source already did, and the run reports the source’s gap rather than filling it (MIDI-BP-03).A
text_retainedcheck of Smallest Image Pixel Value (0028,0106) where the source writes it with VR US although its Pixel Representation (0028,0103) is 1, which makes it SS (PS3.3 C.7.6.3). The rule for a number keeps it (D-022), and the released instance holds the same bytes as its source, which fails the check too.A
text_retainedcheck of a device date or time, such as Time of Last Calibration (0018,1201), which TCIA’s curation keeps. Table E.1-1 gives it X under the Basic Profile, and Modified Dates replaces it with a fixed dummy value by its device role (D-007, D-039), so a released instance fails the check wherever its source held the value, unless Retain Device Identity or Full Dates keeps it without Modified Dates. The benchmark reports such a failure among its deliberate differences, by the action that the run’s policy selects (D-018).
Rationale. The answer keys follow TCIA’s curation of each source collection where it differs from the Basic Profile (D-018), and a TCIA review category marks a check that comes from that curation alone. E.2 names
REMOVEDas the only value for a run that removes or replaces dates rather than modifying them, so writing what TCIA writes would misstate what was done. The MIDI-B challenge’s report (Pei L et al., Medical Image De-Identification Benchmark Challenge, 31 July 2025, arXiv:2507.23608, Section 4.1) notes that its validation script counted non-compliance already present in the input against every participant. A value that the engine made up for an attribute that the source lacks, such as a KVP or an Image Type, would misdescribe the acquisition. Rewriting a kept value’s VR or bytes to suit a reading that the source contradicts would change data that the Profile keeps; how the key’s text reads such a value is not known from the run’s value-free summary, so the difference is attributed to the source’s encoding, not to the engine.Tests. Unit tests show the rules keep KVP, Acquisition Number, Image Type, and Smallest Image Pixel Value, and give Position Reference Indicator X/Z/D; that every released instance of the synthetic collection has
REMOVED(PS3.15-E.2-01); and that an instance written without a required attribute that its source held is sequestered (MIDI-BP-03).
D-032: Residual text explained by kept vocabulary#
Decision.
A text finding inside the data set, which D-027 sends to QC review, is not a reason for review where the kept value it is found in is standard vocabulary or an equipment name, in one of four ways:
Standard term. It is found in an attribute that the pinned dictionary gives VR CS, and every value of that element is an Enumerated Value or Defined Term of that attribute in the pinned PS3.3 or, for Body Part Examined (0018,0015), whose Defined Terms PS3.3 leaves to PS3.16 Annex L, in the pinned Annex L. An element with one value that is not a term is not exempt, since the search records only the first match of a source in each element.
Standard code. It is found in the Code Value, Coding Scheme Designator, Coding Scheme Version, Code Meaning, Long Code Value, or URN Code Value of an item whose Coding Scheme Designator is one that the pinned PS3.16 Table 8-1 lists, such as DCM, SCT, LN, or UCUM. A designator that the table does not list, such as a local one starting with 99, gives no exemption, so the meaning of a local procedure code that holds a description stays under review.
Equipment. It is found in Manufacturer (0008,0070), Manufacturer’s Model Name (0008,1090), or Software Versions (0018,1020), which the Basic Profile keeps, and its source is a private data element or itself names equipment: one of those three, or Secondary Capture Device Manufacturer (0018,1016), Secondary Capture Device Manufacturer’s Model Name (0018,1018), or Secondary Capture Device Software Versions (0018,1019). Any other source, such as Institution Name, Station Name, or a private creator that Table E.3.10-1 does not list, stays under review, since an in-house device or program can carry the institution’s name (D-022).
Vendor private creator. Its source is a private creator element, (gggg,0010) to (gggg,00FF) of an odd group, or Private Creator Reference (0008,0302) in an item of Private Data Element Characteristics Sequence (0008,0300), which names one, and every value collected for the subject at that place is, without trailing spaces and NULs, exactly one of the private creators that the pinned PS3.15 Table E.3.10-1 lists, wherever in the data set it is found. A private creator that the table does not list, such as an in-house or research block’s, or one in another case, stays under review, as does a finding whose source is a private data element, unless D-042’s retained private creator explains it.
Unwritten code meaning. Nor is a text finding a reason for review, wherever in the data set it is, where its source is the Code Meaning (0008,0104) of a code item, every value of that source collected for the subject came from instances that the run does not write, and each came from a code item whose own Coding Scheme Designator (0008,0102), in the same instance, is, without trailing spaces and NULs, one designator that the pinned PS3.16 Table 8-1 lists. Values are pooled across the subject by their place, so each meaning is qualified by its own item before it is pooled, and another instance’s item at the same place qualifies nothing. An instance that the transform sequesters, such as a dose report out of scope or one whose Content Sequence takes D, is not written; one that the run withholds for another reason, such as a copy that conflicts with another or a file that its own gate holds, counts as written, so its values exempt nothing. A kept CT Series Description
AXIAL CHESTthat holdsChest, the meaning of a sequestered dose report’s target region code SCT 816094009, is therefore released. A local designator, such as one starting with 99, or none, as a URN code may have, gives no exemption, as for a standard code, and free text from the same instance, such as a TEXT content item’s value, still goes to review.Nothing else changes: a person name, UID, date, datetime, or direct identifier found anywhere, and any value found outside the data set, still withholds the file, and other text findings still go to review. There is no setting that adds or removes an exemption.
Kept values are read from the written file’s bytes as ISO 646 text, never decoded by pydicom; a finding in an element with any other byte is not exempt under any of the four, even where the file declares a character set that holds it. Each exempted finding stays in the search, which the QC pack lists with its excerpt (D-016), and the release condition records why each was exempted.
The release report counts the released instances with an exempted finding, in its
exempted_findingssection: by the exemption, which is one of these five, a date that Modified Dates shifted (D-039), a value that a selected option keeps (D-042), a UID that a selected option keeps, found from instances that the run does not write (D-042), text in a private creator that the run’s safe private list keeps (D-042), or a UID that a selected option keeps, found from a private copy that the run removes (D-042); by the attribute of the source value; and by the attribute in which the finding is, each by its tags without items; each instance once for each, however many of its items or values have it. It names no value or instance. A held or sequestered instance is not counted, since its exemptions release nothing; the QC pack lists every finding, exempted or not, by instance and place.The terms are generated from the pinned PS3.3 with the other tables (D-001): each list titled “Enumerated Values” or “Defined Terms”, including “Retired Defined Terms” and lists for one value, in an attribute’s row or in a section that its row refers to, and each list whose title names attributes by tag, which gives its terms to those attributes; a tag after “if” or “when” in a title is a condition. Terms are kept for the attributes of VR CS, apart from repeating groups, where VR CS can hold them. In 2026d this gives 2,549 terms of 655 attributes. Body Part Examined’s terms are generated from the Body Part Examined column of Annex L’s Tables L-1, L-2, and L-3, for human, large animal, and small animal use, skipping rows that give a code but no term: 347 terms in 2026d. Terms that PS3.3 gives only by reference to any other part are not generated, so findings in such attributes stay under review.
The maintainer decided on 11 October 2026 to exempt both standard vocabulary and equipment names, over exempting only one of them or keeping the holds with a list of reviewed texts, and to exempt the private creators that Table E.3.10-1 lists while still searching for them, over keeping them under review, no longer searching for any private creator, or exempting every Coding Scheme Designator.
The maintainer decided on 26 October 2026, at 06:46:02 UTC, to exempt a finding whose only source is a Code Meaning in instances that the run does not write, coded meanings only and not free text, over keeping such holds. The exemption reads a standard code as the standard code exemption does, so a local scheme’s meaning, which can be the site’s own text, stays under review.
Rationale. On the MIDI-B benchmark of 10 October 2026, residual text findings held 96% of the withheld instances in the Validation subset and 95% in the Test subset. Judged by where they were found, though not by their values, which the benchmark does not report, almost all were a removed value equal to a coded term, a defined term, or a device name that the profile keeps elsewhere, such as a removed Scatter Correction Method found in a kept Collimator Type, or a vendor’s private element found in Manufacturer’s Model Name. Such holds put the review effort on findings that reveal nothing. A kept CS value made only of its attribute’s own terms is set by the standard’s vocabulary, so a removed value found in it reveals nothing that the term does not. Exempting every CS value was rejected: sites write their own text in CS attributes, such as a procedure in Body Part Examined, which stays under review unless every value is one of Annex L’s terms. D-027’s example of
CHESTfound inCHESTABDOMENis released, sinceCHESTABDOMENis an Annex L term, and a removed value found inside a term reveals no more than the term does. Table 8-1 lists the schemes that the standard registers, so a code of one is shared vocabulary, while a local scheme’s meanings are the site’s own text. The equipment names are kept by the Basic Profile, and a vendor’s private element or another equipment attribute holding the same name adds nothing to them; an institution’s name in them is what the profile removes elsewhere, so that stays under review. Deciding D-027’s open question broadly, so that a removed value equal to a kept one is not searched, was rejected because it would also release a local procedure code’s meaning that copies a free-text description; and a list of reviewed texts, like the reviewed ROI names (D-009), was rejected for now because the benchmark’s score would rest on a manual step. The residual risk is free text that a site writes as the Code Meaning of a code of a registered scheme, or in an equipment name with a vendor’s private copy, which is released without review. With the three exemptions and a separate fix for MR instances, the benchmark run of 11 October 2026 released 86.7% of the Validation subset’s instances and 84.0% of the Test subset’s, against 16.0% and 22.3% in the run of 10 October without either; the independent validators (D-030) reported nothing unexplained in the released instances, and NCI’s validation script found no failure in any HIPAA category. Exempting standard vocabulary alone or equipment names alone was estimated to release about a third of each subset, since most held instances had findings of both kinds. The private creators that Table E.3.10-1 lists are vendors’ labels that the standard itself prints, so finding one reveals the vendor, which Manufacturer keeps; the benchmark found removed private creators in kept local Coding Scheme Designators, though it does not report which. In the benchmark run of 11 October 2026 on both subsets, this exemption released no further instance, so every instance that it could affect is also held by another finding, or its private creator is not exactly one that the table lists. (0008,0302) holds the same label as the creator it names, and is removed with its sequence (D-028), so under Retain Safe Private (D-035), where the creator of a block that the sequence describes is kept, it would otherwise send every such instance to review for a label the standard prints; it takes the exemption under the same condition, so a creator that the table does not list in it stays under review. Still searching for them keeps each match in the QC pack, whereas no longer searching for private creators would also stop searching for an in-house block’s, which can name the institution, and exempting every designator would release a local designator that abbreviates the institution. Counting the exempted findings in the release report lets a recipient, who does not see the QC pack, weigh that residual risk: how many released instances rest on each exemption, and in which attributes. Counting instances by attribute, as the report counts values not searched (D-027), names no value, and counting released instances alone keeps the count to what the exemptions released. A sequestered instance’s removed values are still searched for in its subject’s written files (D-027), so before the unwritten code meaning exemption the target regionChestof a dose report that is not released held a kept CT Series DescriptionAXIAL CHESTfor review, and every chest CT with a dose report would have gone to review for a word that the standard defines. That exemption is decided by the finding’s source rather than by where it is found, since the kept value that holds it can be free text: what makes the finding harmless is that its removed value is a registered scheme’s meaning and that no released instance held it. Exempting every value of an instance that is not written was rejected, since its free text can hold a name that a kept description repeats, which is what the search is for; a local scheme’s meaning can be such text too. Counting a withheld instance as written unless the transform sequestered it keeps every other withheld instance’s values searched for as before.Tests. A removed value found in a CS value whose every value is a term of its attribute is released, with the finding kept in the search and its exemption recorded, while one found in an element with a value that is not a term, or that is a term only of another attribute, or in Body Part Examined that is not one of Annex L’s terms, goes to review, while one found in Body Part Examined that is, as in D-027’s example, is released; a person name found in a term still withholds the file; a removed value found in a code item under a designator of Table 8-1 is released, and one under a designator that the table does not list, under one in the wrong case, or under none, and one in a code element outside an item, goes to review, as does a local designator found in a kept local designator; a removed value found in an equipment name is released when its source is a private data element or an equipment attribute, and goes to review when its source is Institution Name, Station Name, or a private creator, or when it is found in other kept text; a finding in a kept value outside ISO 646 is not exempt, by a term, a code, an equipment name, or a vendor’s private creator, in a file that declares its character set; the Basic Profile keeps the equipment names; the terms generated from the pinned edition include spot terms from rows, from sections that rows refer to, and from lists that name their attribute, and none for attributes of other VRs, and Body Part Examined’s terms come from PS3.16 Annex L, not PS3.3; and generation keeps only terms that VR CS can hold, gives a list that names an attribute to it rather than to the row, treats tags after “when” as conditions, leaves out lists with other titles, attributes of other VRs, and repeating groups, and fails on a page that gives no terms; and Annex L’s terms are generated from each table’s Body Part Examined column, skipping rows without a term, and fail where a table has no such column, a term is one that VR CS cannot hold, or no table gives a term; and a removed private creator that Table E.3.10-1 lists is released wherever it is found, while one that the table does not list, one in another case, a private data element holding the same text, and a place whose pooled values are not all listed creators go to review; and so is a removed Private Creator Reference of (0008,0300) that the table lists, found in a kept private creator, while one that the table does not list, and the same value outside that sequence, go to review; and the release report counts the released instances with each exempted finding by exemption, source attribute, and attribute found in, each instance once however many items of one sequence have it, and the same place in another instance apart; a run that releases a removed Secondary Capture Device Manufacturer found in the kept Manufacturer of three CT slices counts three and names neither value in either form of the report; held and sequestered instances and identical copies are not counted; findings not given by instance, a finding outside a data set element, and an exemption, attribute, or count of another form are refused; and the report’s human-readable form shows each count as a row; and under Clean Descriptors, CT slices whose kept Series Description holds the meaning of a sequestered dose report’s target region code are released, with the finding exempted as an unwritten code meaning and counted in the release report, while the same meaning under a local designator or none, a URN code’s meaning without a designator beside another sequestered instance’s SCT item at the same place, whether its meaning is the same or another, a meaning also collected from a written instance, and a free-text value of the same report, go to review, and an instance that the transform writes gives no value as unwritten.
D-033: Option sets chosen per run#
Decision.
A run’s policy is that of a preset or of a custom option set, never both. The library’s
deidentifytakesoptions, the names of options of Table E.1-1 or of the Clean Pixel Data and Clean Recognizable Visual Features Options (D-011), in place ofpreset, and the command takes--option NAME, once for each option, in place of--preset, which takes any of the four presets; with neither, a run appliesbasic. A custom option set is composed and validated as D-011 describes, so a conflict between two of its options is rejected, including those thattps-importresolves, and its policy can claim conformance.A custom option set is enabled only while
basicis enabled, since every policy applies the Basic Profile, and each of its options is enabled. An option is enabled once its behaviour is implemented and validated for the documented input scope, as a preset is, including a conformance statement for the option alone that lists nothing under “Not yet described”; only an option that the engine applies can be enabled (D-011). No option is enabled yet. Enabling a preset enables none of its options, and enabling options enables no preset.A run under a custom option set that is not enabled is refused before anything is read, with a message that names the Basic Profile where
basicis not enabled, each of its options that is not, and the options that are. The command line treats a preset given with options, and an option that is none of these, as argument errors, and a policy that is not enabled, or whose options conflict, as a run that could not start; the library raisesValueErrorfor a preset given with options,TypeErrorfor options given as a single string, andDeidentifyErrorwhere the policy is not enabled or cannot be composed. The ROI name arguments apply under a custom option set exactly where it selects Clean Descriptors (D-009).A run whose policy selects Clean Pixel Data makes the text detector with the pinned model (D-037), after reading everything else that the run is given, since making it can download the model. The command’s
--redaction-review DIRECTORYgives the run the attested QC pack whose redaction verdicts apply (D-048), and--region-rules FILEthe custodian’s reviewed region rules (D-037), which must exist, since a run records no rule, and lie outside the source, the release and its staging area, and the QC destination, as the reviewed-names list must. Each applies exactly where the run’s policy selects the option, as the ROI name arguments apply under Clean Descriptors, and is an argument error otherwise. A pack or store that cannot be used, or a detector that cannot be made, stops the run before it starts, with a message that names no path. The library’sdeidentifymakes the detector in the same way, since it builds its transform through the same function, and takes the pack asredaction_reviewand the store asregion_rules, under the same conditions; it raisesValueErrorfor either without the option, before anything is read, andDeidentifyErrorfor a pack, store, or detector that cannot be used.A run under a custom option set is marked, reported, and described as one under a preset is, with no preset: its De-identification Method names a custom option set (D-012), its release report’s
policysection gives no preset and the options, and its conformance statement is for a custom option set.Nothing reaches the
pymedphyscommand line before the first supported release (Scope).The maintainer decided on 12 October 2026 to let a run choose its own set of options, over keeping presets only.
Rationale. On 12 October 2026 the maintainer asked for every de-identification option that PS3.15 describes. Table E.1-1’s ten options, two of which exclude each other (E.3.6), allow 768 sets before conflicts between options are rejected. A preset for each set that someone needs would multiply names that say less than the options do, while naming the options states exactly what is applied, as the naming principle under Presets asks of a preset named after a profile. Keeping presets only, as D-011 had it, would leave five of the ten options in no preset, and the others only in the combinations that the presets fix. Enabling each option once, rather than each set, is sound for the actions: composition rejects every attribute to which two selected options give different actions, and any conflict among several options is one between two of them, so each attribute of a set that composes takes the action of one option, or the same action from each option that gives one. In the engine as built, each item that a statement lists under “Not yet described” belongs to every policy, to one selected option, or to
tps-importalone, so while the statements ofbasicand of each option alone are complete, so is that of any set of them that composes; the tests check each. Requiringbasickeeps a custom option set from applying the Basic Profile before the preset that applies it alone is validated, and a set of no options is the Basic Profile under another name. Refusing a preset given with options, rather than adding the options to the preset’s, keeps each policy one that its name or its list of options states in full.Tests. No option is enabled yet, and every enabled option is one that the engine applies; a custom option set of enabled options is selected, with no preset and its options in the table’s order, including the empty set as the Basic Profile alone, and is refused while
basicor any of its options is not enabled, naming each, also where a preset with the same options is enabled; a preset given with options, an unknown option, a single string, both Retain Longitudinal Temporal Information Options, and conflicting options are refused even with every option enabled; an enabled option that the engine does not apply is still refused by the engine; the command builds the transform of its options, takes the ROI name arguments only with Clean Descriptors among them, rejects a preset given with options and an unknown option as argument errors that quote nothing, exits with status 3 before loading anything when an option is not enabled, and names every option, and every preset with its use, in its help; it takes each preset, building the preset’s transform once it is enabled and exiting with status 3 before anything runs while it is not, and names each preset that selects Clean Descriptors where it rejects the ROI name arguments; under Clean Pixel Data, and only then, the command makes the text detector and uses the custodian’s region rules, whose regions a run blacks out beside the detector’s, and an attested pack’s verdicts, which release an accepted image with its reviewed regions and sequester a rejected one; it exits with status 3, naming no path, for a store that does not exist, lies where a run writes, or is malformed, a pack that holds no QC pack or is not attested, and a detector that cannot be made or whose model cannot be read, reading the pack and the store before making the detector, and treats a redaction review or region rules without the option as argument errors; the library makes the detector under the option, uses the custodian’s region rules and an attested pack’s verdicts as the command does, raisesDeidentifyError, naming no path, for a store that does not exist or is malformed and a pack that holds no QC pack, and refuses either without the option, creating nothing; a custom option set runs end to end, with no preset in the release report and a statement for a custom option set; the library refuses a preset given with options and a single string, reads its options once, and releases the same outcomes under a custom option set of Clean Descriptors as underbasic-clean-descriptors; and each enabled option alone has a complete statement, and an enabled custom option set’s statement claims its options.
D-034: Cleaners for C, and AE titles under Retain Device Identity#
Decision.
C is settled by reviewed cleaners, each for the attributes that one option gives C, with its method in a module of its own, and all listed in one registry (
cleaners.py). Each entry names the option, the attributes it cleans by their tags in Table E.1-1, the VRs it reads them in, and its method, which the conformance statement gives. A run applies the cleaners of the options its policy selects to each instance’s edits, wherever the attributes are in the data set, before descriptor cleaning (D-009). A cleaner that may write a value equal to its source marks the attribute as retained, so that the residual search leaves the source value out, as it does a ROI Name that descriptor cleaning keeps (D-027). Most cleaners clean each value on its own, from the value and the run’s key. A cleaner whose values depend on each other or on the subject, such as one that moves an instance’s dates by its subject’s offset once they are in its local time, cleans the whole instance instead: it is given the source value of every attribute that it is to settle in the instance, in file order and in any VR that it reads, bytes included, with the run’s key and the subject’s identity, and returns, for each attribute that it settles, the values written and whether they are the source’s own; an attribute that it leaves out stays pending.An attribute given C that no cleaner settles stays pending, and so does one whose value was not collected or was read in a VR that its cleaner does not read. Under Clean Descriptors, descriptor cleaning cleans it where it is a free-text descriptor whose values it can clean, and otherwise gives it the action that the policy gives it without that option, where that action is not C (D-009); otherwise the instance is sequestered. Under a Retain option, writing it with the option’s code would claim a retention that did not happen (D-011), and writing it without the code would claim that the Basic Profile removed values that the option keeps (D-012).
The first cleaner is Retain Device Identity’s. Table E.1-1 gives C under that option to eleven attributes of VR AE, which name an application entity or a network: Retrieve AE Title (0008,0054), Station AE Title (0008,0055), Network ID (0008,1000), Scheduled Study Location AE Title (0032,1021), Scheduled Station AE Title (0040,0001), Performed Station AE Title (0040,0241), Selector AE Value (0072,005E), Receiving AE (0074,1234), Requesting AE (0074,1236), Originator (2100,0070), and Destination AE (2100,0140). Each value becomes a token of the run’s key:
AEfollowed by the first 14 characters of the base32 encoding of the value’s HMAC-SHA256 in theae-titledomain, once the leading and trailing spaces that VR AE makes insignificant are removed, which is 16 characters, the most that VR AE allows. Each value of a multi-valued attribute gets its own token, an empty value stays empty, and an attribute with no value is written with none. Within a run, an application entity has the same token in every attribute and instance; across runs, whose keys differ, tokens are unrelated (D-004). The token’s prefix and length are parameters of generated values, and its domain is one of the key’s derivation domains, so the method digest covers both (D-024).The conformance statement gives, for each selected option that has a cleaner, the attributes that the policy gives C and the cleaner cleans, and its method. It lists the manner of cleaning as not yet described only for an attribute given C that no cleaner cleans and that Clean Descriptors’ fallback does not settle.
Residual findings. Under Retain Device Identity, a station’s AE title often equals its Station Name (0008,1010), which the option keeps, so the residual search finds the AE title’s source value in the kept Station Name; D-042 decides when a finding inside a value that an option keeps is a reason for QC review.
Rationale. E.3.8 has AE titles “Cleaned, rather than just Kept, since they may contain embedded institution or person identification information”, and C replaces a value “with values of similar meaning known not to contain identifying information and consistent with the VR” (Table E.1-1a). A keyed token keeps what the option needs of an AE title, which application entity an instance names, consistently across the run’s instances and attributes, such as a Performed Station AE Title that names the same entity as a Station AE Title, while it holds nothing of the value but a keyed digest, as replacement UIDs (D-003) and patient pseudonyms (D-005) do. Removing the attributes was rejected, since the option retains the device’s identity; keeping them, since E.3.8 does not allow it; and one dummy value, since every application entity would then look the same. A reviewed list of AE titles to keep, as the reviewed-names list keeps ROI Names (D-009), may be added later; a token needs no review. Seventy bits of digest make a collision among a thousand distinct application entities less likely than one in 10^15. A registry, rather than a branch of the transform for each option, lets each option’s cleaner be reviewed, tested, and described in the statement from one entry, and lets the options be built in parallel.
Tests. A token is a valid AE value of 16 characters, derived as the conformance statement says, the same for a value with or without leading and trailing spaces, and different for another value or another key; each value of a multi-valued attribute gets its own token, and an empty one stays empty; no two cleaners clean the same attribute, each cleans only attributes that its option gives C, in the VRs that the pinned dictionary gives them, and every attribute that Retain Device Identity gives C has a cleaner; cleaners settle only the pending C of their attributes, leave one whose value was not collected or was read in another VR pending, and leave a retaining cleaner’s attributes out of the residual search; a cleaner cleans single values or the whole instance, not both; a cleaner of the whole instance is given every pending value in the VRs it reads, with the key and the subject’s identity, and settles only those it returns, leaving out of the search those it says are the source’s own; under Retain Device Identity a plan’s Station Name and Device Serial Number are kept and its AE titles are written as tokens, the same in every instance of the run, with the option’s code; under Clean Descriptors as well, AE titles are cleaned before descriptors fall back, and the instance claims both options; an instance with an attribute that Retain Patient Characteristics gives C, which no cleaner cleans, is sequestered; the statement for Retain Device Identity gives the cleaner’s attributes and method and lists nothing as not yet described, a preset without such an option describes no cleaner, and
tps-importstill lists the manner of cleaning its dates and patient characteristics; and changing the token’s prefix or length changes the method digest.
D-035: Reviewed safe private rules#
Decision.
The L2 file
safe_private.toml, curated by hand for the pinned edition, gives a rule to every row of PS3.15 Table E.3.10-1 and to each reviewed addition. A rule is keyed by private creator, odd group, and element within the block, so it applies in whichever block its creator reserves (Architecture item 6). A creator matches exactly, apart from trailing spaces and NULs, as D-032 matches the table’s private creators.Table E.1-1 gives retained private attributes C, so each rule says how a retained value is handled:
numeric: FD, FL, SL, SS, SV, UL, US, UV, and AT values, and IS and DS values that are valid numbers of their VR, are kept;code: CS values made only of the characters that VR CS allows are kept;uid: UI values are replaced, as every other UID is (D-003), and a value read without its VR, from Implicit VR Little Endian or as UN, is removed, since the engine replaces only a UID that it reads as UI;text: LO, LT, SH, ST, UC, and UT values are cleaned as descriptors are (D-009) under Clean Descriptors, as below, and removed without it;sequence: the items of an SQ value are parsed, and each nested attribute is handled on its own merits (E.3.10), so the sequence is kept as a container only where the source holds its items;remove: the attribute is not retained.
A rule takes the handling of its VR unless its note says why not, and every other VR, alternatives such as OW/OB, and a row for which the table gives no VR can only be removed. In 2026d, the 479 rows give 280 numeric rules, 65 code, 55 sequence, 44 text, 7 UID, and 28 that remove: 25 for OB, OW, OW/OB, or no VR, and 3 numeric rows that can hold absolute times, Mid Scan Time (0019,xx24) of GEMS_ACQU_01 and the two timestamp elements (0149,xx02) and (0149,xx03) of SIEMENS Ultrasound SC2000.
A reviewed addition, for a private attribute that the table does not list, must retain its value and cites the public document that shows it is safe, such as a vendor’s DICOM Conformance Statement, with a note. The file has none.
TCIA’s Private Tag Dictionary, the list that TCIA uses to curate its collections under this Option, is a second list that a run may choose instead of
safe_private.toml, which stays the default. It is not a source of reviewed additions.The file
TCIAPrivateTagKB-02-01-2024-formatted.csvships unchanged in_tcia/, with TCIA’s attribution and the CC BY 3.0 licence under which TCIA publishes its site inLICENSE-CC-BY-3.0.txt, and the package’s licence expression includes CC-BY-3.0.tcia_private_tags.PINrecords its URL, length, and SHA-256, andload_tcia_private_tagsrefuses a copy that does not match.pymedphys dev tcia-checkdownloads TCIA’s file and compares its length and SHA-256, and the shipped copy’s, with the pin, and checks that TCIA’s page still links that file and no edition not yet reviewed, and links that licence. The TCIA Edition Check workflow runs it each month, opening or updating one issue when it finds a change or cannot check, and on pull requests that change the dictionary, its loader, or the check, or that carry thecheck-upstreamlabel, where its result is advisory for the reviewer rather than a required check. Merge groups do not run it, so TCIA’s availability cannot block them.Each row gives an attribute’s path, from the top level down through the sequences that hold it, with its VR and a disposition. The loader reads every row: of 8,787, 3,836 keep their attribute, and 6,568 are at the top level. A creator matches as in
safe_private.toml; rows that write a creator in upper case match only that.A disposition of
kis a basis for retaining an attribute, not a handling: a value that the dictionary keeps still passes the handling of its VR, as a rule ofsafe_private.tomlwould give it, so its OB, OW, and UN values are removed, and its text is cleaned only under Clean Descriptors, as below.The rules of a run that chooses it are made from the rows at the top level whose creator is compared as below (
tcia_private_tags.tcia_safe_private_rules). A row below the top level makes none, so an attribute that only such a row keeps is removed, and a rule made from a top-level row applies wherever its creator’s block is, as a rule ofsafe_private.tomldoes. The dictionary gives an attribute a row for each VR that TCIA has seen it with, such as DS with OB and UN, so a rule is chosen by VR: an attribute written with a VR takes the rule of the row for that VR, and has none where no row gives that VR; one whose VR is not written, in Implicit VR Little Endian or as UN, takes the rule of the one VR other than OB, UN, or none that its rows give, and has none where they give several or none. A kept row’s rule has a single value as its VM, or the handling and VM of the rule ofsafe_private.tomlfor the same creator, group, element, and VR where there is one. Any other row’s rule removes its attribute, as does a VR whose rows disagree.A run chooses it in place of
safe_private.tomlbySafePrivateList.TCIA, which the transform, the command’s--safe-private-list tcia, and the library’ssafe_private_list="tcia"take, and which is refused without the Option. Declarations in (0008,0300) apply under either list, as below. The run’s method digest and release report record which list it used (D-024), and its conformance statement names the file, its date of retrieval, and its SHA-256, gives TCIA’s attribution, and lists each rule that can retain an attribute with TCIA’s name for it. Benchmark results are to report the two lists separately; the MIDI-B benchmark cannot yet score this Option.
pymedphys._dicom.deidentify.safe_private.load_safe_private_rulesrejects a file that covers another edition, lacks a rule for a row of the table, gives a row another VR or VM than the table, gives a handling that cannot check a value of its VR, departs from its VR’s handling without a note, or adds a row of the table. So a new edition fails to load until each new or changed row has been reviewed.The engine applies the rules under the Option, at the top level and in the items of every sequence that is kept (
retained_private.py):A data element’s rule is the one for the private creator that reserves its block in the same data set or item. A creator is compared only where its value, without trailing spaces and NULs, is printable ISO 646 without a backslash, written as LO or without a VR, and the loader rejects a rule whose creator is outside that repertoire.
A rule settles its attribute only where the attribute is written with the rule’s VR, or without one, in Implicit VR Little Endian or as UN, and its value passes its handling’s check, with a number of values that the rule’s VM allows. Any other is removed.
A private creator is kept only where an attribute of its block in the same data set or item is kept, replaced, or cleaned.
A kept private value whose VR is not written, in Implicit VR Little Endian or as UN, is read by its rule’s VR, and a kept private creator as LO, so that each kept creator, code string, and number string is among the retained strings that the QC pack lists for review (D-017), as it would be with its VR written. A sequence holds no value of its own, so it is given no VR, and a kept sequence whose items cannot be read sequesters its instance with its VR in the release report as written, or none where the file writes none (D-026). Kept binary numbers (FD, FL, SL, SS, SV, UL, US, UV, and AT) and kept sequences are not among the retained strings, as no binary value or sequence is (D-017): a binary value’s check is only that it is a whole number of values within its rule’s VM, so its retention rests on the reviewed rule alone.
A private sequence that no rule lists is parsed, as E.3.10 asks of one “not known to always only contain safe content”, where its block’s creator is compared: it is kept as a container, so that each attribute in its items, standard or private, takes its own rule at every depth, and the instance is planned again with it removed, with everything in it, where nothing in its items other than a private creator is kept, replaced, or cleaned. Its creator is then kept only for what its block keeps. A private sequence in a block without a creator that is compared is removed with everything in it, as is any other private attribute there. A kept creator that no rule names is among the retained strings that the QC pack lists for review.
An instance’s Private Data Element Characteristics Sequence (0008,0300), at the top level in the SOP Common Module, is read for what it declares about the blocks that its items name by Private Group Reference (0008,0301) and Private Creator Reference (0008,0302), the creator compared as above, wherever such a block is:
An attribute that holds a value is declared safe where Block Identifying Information Status (0008,0303) is SAFE, or MIXED with the attribute listed in Nonidentifying Private Elements (0008,0304). It is declared possibly identifying where the status is UNSAFE, or MIXED without the attribute listed, or where Identifying Private Elements (0008,0306) of an item of Deidentification Action Sequence (0008,0305) lists it. Where items disagree, possibly identifying wins. An item that names a block but whose status is not one of those Enumerated Values, or whose list of attributes cannot be read, declares every attribute of the block possibly identifying.
An attribute declared possibly identifying is removed, even where a rule would keep it.
An attribute declared safe that no rule lists takes the handling of its VR, as a rule for a row of Table E.3.10-1 does: its VR as written, or, where the file does not write one, the VR that Private Data Element Value Representation (0008,030A) defines for it in Private Data Element Definition Sequence (0008,0310). It is removed where neither gives a VR, the two differ, or two definitions of it in (0008,0300), in one item or in two, disagree in VR or VM, or one names it but cannot be read, in Explicit VR as in Implicit. Its number of values must fit the VM that Private Data Element Value Multiplicity (0008,0309) defines with that VR, or a single value where (0008,0310) gives none, or gives a VM that PS3.6 has no form for, such as 1 to 7 in steps of 2. So a declared number or code string is kept, a declared UID replaced, declared text cleaned as a rule’s text is, and every value of another VR, such as a date, a name, or OB, OW, or UN data, removed.
A private sequence is parsed as above whatever (0008,0300) declares of it.
The values read are those of these attributes, which describe private blocks rather than the patient. The sequence itself is removed by its supplementary rule (D-028).
Under Clean Descriptors too, text that a rule retains is given C where it is written with the rule’s VR and with a number of values that the rule’s VM allows, counted by the backslashes in its bytes; since a byte 5CH within a character of a multi-byte character set can raise that count, cleaning counts the decoded values against the VM again, and text that does not meet it takes its action without the option. Descriptor cleaning settles it as a free-text descriptor (D-009), by the reviewed descriptors list’s decisions on its private attribute’s key, which names the creator as compared, the group, the element within the block, and the VR; the technique vocabulary (D-036) keeps none of it. Where cleaning does not write it, it takes its action without Clean Descriptors and is removed, as is a creator that its block kept only for it, and a parsed private sequence that the policy without the option removes goes with everything in it, text that a reviewer kept included, as a cleaned descriptor in a sequence that another’s action removes does. Since cleaning can so remove a creator that the plan keeps, each kept creator is collected for the residual search where the plan cleans private text, and left out where it is written, so that one removed is searched for, as a removed creator is (D-027). Text that cannot be decoded in its character set, or that is outside ISO 646 where no Specific Character Set applies, is read as removed text is, read as ISO 8859-1 for the residual search, and removed, rather than sequestering the instance. Text written without its VR, in Implicit VR Little Endian or as UN, is removed, since only the VR as written decodes it, and the writer would otherwise have to give the file a VR it did not hold. The QC pack lists each value with its key (D-016), the release report counts the values with those of the other descriptors, a kept value is left out of the residual search and listed as a retained string, as a kept descriptor’s is (D-017, D-027), and the rest of what is written is searched as before.
Every other private attribute is removed, which E.3.10 allows in place of processing it as Deidentification Action (0008,0307) recommends.
The conformance statement describes how the rules are matched and applied, and lists each rule that can retain an attribute, with the meaning that Table E.3.10-1 gives it or the source of the addition; the rules for text are among them only under Clean Descriptors.
Rationale. E.3.10 retains the private attributes “known by the de-identifier to be safe”, and lists four ways of knowing, of which Table E.3.10-1 is one. The Note to the table calls it “a sample list of Private Attributes thought to be safe”, which vendors do not guarantee, suggests retaining numeric values only, with code strings a possible exception, and calls bulk binary data particularly unsafe, since it can hold whole proprietary headers that include the patient’s name. Following the Note keeps what E.3.10 names as the Option’s purpose, such as CT helical pitch and PET SUV factors, while retaining nothing that cannot be checked. Retaining every row as listed was rejected because the table lists values that cannot be read or checked, such as a whole stress study file (OW) and ultrasound volume payloads (OB), which the residual search also leaves out (D-027). Code strings are retained because the Note allows them and VR CS holds at most 16 upper-case letters, digits, spaces, and underscores; a name written in one is still found by the residual search where the same name was removed elsewhere (D-027). Text is cleaned rather than kept, as the Note advises, so the descriptor cleaner’s review applies to private text too. It is cleaned only under Clean Descriptors, since the reviewed descriptors list, the pooled human review that D-009 requires before free text is retained, is given to a run only with that option, and removed otherwise, as E.3.10’s “removed or processed” allows. A decision names a private attribute by its creator and element within the block rather than its tag, as a rule does, since the tag depends on the block that the creator reserves, and by its VR, since a list’s rules are chosen by VR; the form follows the paths of TCIA’s dictionary. The technique vocabulary’s words are reviewed for the standard’s technique descriptors, whose meaning the standard defines, and say nothing of what a private attribute holds. Private text that cannot be decoded is removed rather than sequestering its instance, as an undecodable descriptor does, because removing it is what the Option did before it could be cleaned and loses nothing that the instance’s IOD requires. The three timestamp rows depart from the table because an absolute time would carry the acquisition date and time that the Basic Profile removes, and no reviewed document shows that they are relative. Keying by creator and element within the block follows MIDI §1.17.3, since a vendor’s block can be reserved at any of (gggg,0010) to (gggg,00FF). Creators are compared only in printable ISO 646 without a backslash, as their bytes, because every character set that DICOM allows reads those bytes as the same characters without an escape sequence, so no private text is decoded and no two creators that differ in their bytes can match one rule; every creator of Table E.3.10-1 is in that repertoire. Parsing a private sequence that no rule lists, rather than removing it whole, follows E.3.10’s text, as the maintainer decided on 13 October 2026. It is kept only where something in it is kept or replaced, because an emptied attribute, a dummy value, and a private creator carry nothing that the Option retains, and a creator that no rule has reviewed should not be kept for an empty container; a value that is emptied or given a dummy value is still searched for by the residual search (D-027). Only a block whose creator is compared is parsed, so that every kept sequence has a creator that defines it, as E.3.10 requires of the retained attributes, and no creator is kept whose bytes might read as different characters in another character set. Honouring what an instance declares about its own private blocks follows E.3.10’s first way of knowing, as the maintainer decided on 12 October 2026. A declared attribute takes the handling of its VR, because the declaration is a basis for retention as a row of Table E.3.10-1 is, and the table’s Note applies to it alike: numbers and codes can be checked, while text, dates, and bulk binary data cannot, and a date would carry what the Basic Profile removes. Its VR must be known, from the file or the sequence, because a value that cannot be read by its VR cannot be checked. A declaration that an attribute may identify defeats a reviewed rule, because the attribute is then not known to be safe, and removing it is what E.3.10 asks of every other private attribute; the maintainer decided on 13 October 2026 that the file’s flag wins, over letting the reviewed rule keep the attribute, at the cost of such a value as a PET SUV factor in a file that flags its block. Sequences are parsed whatever is declared of them, as E.3.10 suggests even of nominally safe ones. Only the top-level sequence is read, since PS3.3 places it in the SOP Common Module, and it applies wherever its creator’s block is, since PS3.3 identifies a block by its creator rather than by where it is reserved. Taking additions only from public documents keeps every retained attribute traceable to a source that anyone can check. TCIA’s dictionary is offered as a choice, not merged into the default, as the maintainer decided on 12 October 2026: it covers many more attributes than Table E.3.10-1, but by TCIA’s curation rather than by public vendor documents, and it keeps bulk binary data that the Note calls particularly unsafe. Its rules are chosen by VR because its rows record the VRs that TCIA has seen an attribute with, including OB and UN for files that held it without a readable one, so only the row for the VR that reads the value says whether that value may be kept, and where the VR is not written, only a single readable VR says how to read it. A kept attribute has a single value unless a reviewed rule gives its VM, because the dictionary gives no VM, and a long array kept on its word alone would not have been checked as a reviewed rule’s values are, as for a declared attribute; where a reviewed rule covers the same attribute and VR, its handling and VM are the reviewed knowledge of that value. Only rows at the top level make rules, because a rule applies wherever its creator’s block is, and a row whose path runs through a sequence says nothing of the block elsewhere. Declarations still apply, because they are another way of knowing, and the maintainer’s decision that the file’s flag wins does not depend on the list. It ships, rather than being downloaded when used, so that a run works offline and the package fixes which list a run used; the pin and the edition check keep the shipped copy identical to TCIA’s file. The check runs on a schedule and on the pull requests it concerns, not in every merge group, as the maintainer decided on 12 October 2026, so that an outage of TCIA’s site cannot block unrelated changes. Its pull request result is advisory because TCIA’s site does not always answer GitHub’s runners: on 12 October 2026 it timed out from them twice in four hours while answering elsewhere.
Tests. Every row of Table E.3.10-1 has one rule, with the table’s VR and VM; each rule takes its VR’s handling except the three timestamp rows, which have notes; every OB, OW, OW/OB, and no-VR row is removed; the PET SUV factors, CT pitch, and table speed are numeric; the handlings follow the Note for every VR, and only removal does not retain; a rule applies in whichever block its creator reserves, ignoring only trailing spaces and NULs, and not under another case, a leading space, another creator, another group, or another element; a lookup outside a private block is refused; a reviewed addition is read with its source and retained; the shipped file has no addition; and a file is rejected for each problem that its loader lists, including a creator outside printable ISO 646. Under the Option, the engine keeps numbers and code strings with their creators, in Explicit and Implicit VR Little Endian, in each block on its own, ignoring a creator’s trailing spaces and NULs but not its case; compares only creators in printable ISO 646 without a backslash, and none written with another VR; removes an attribute written with another VR or with a number of values that its VM does not allow, a value that fails its check, text, an attribute that its rule removes or that no rule lists and that is not a sequence, one whose block has no creator, and each element that PS3.5 does not allow; replaces a UID written as UI and removes one read without its VR, and one with more values than its VM allows; parses a listed private sequence at depth 1 and 2, leaving the standard attributes in its items to their own rules, and removes one written with another VR; parses a private sequence that no rule lists, in Explicit and Implicit VR Little Endian, keeping it and its creator where a private or standard attribute in its items is kept, at depth 1 and 2, keeping each enclosing sequence that no rule lists, and removing it with its creator where its items keep only emptied or removed attributes and the creator of a nested sequence that keeps nothing; removes a private sequence whose block has no creator or one outside printable ISO 646; keeps a private block in the items of a standard sequence; writes no value that it removes; lists each kept creator, code string, and number string, and each value of one with several, among the QC pack’s retained strings, at the top level and in an item, in Explicit VR Little Endian, written as UN, and in Implicit VR Little Endian, including a creator padded with a NUL, creators written as UN at the top level and in items at depth 1 and 2, and a creator that no rule names kept for a parsed sequence, written as LO or as UN; reads each kept creator, code string, and number string without its VR as it reads the same value written with it, without the spaces around each value of an integer or decimal string; and gives the VR that reads each kept value written without one, LO to each kept creator written as UN, and none to a sequence, so that a kept sequence, listed or parsed, whose items cannot be read sequesters its instance with SQ, UN, or no VR in the release report, as Explicit VR Little Endian, UN, or Implicit VR Little Endian writes it. Under the Option, an attribute that the instance declares safe, in a block marked SAFE or listed in Nonidentifying Private Elements of a MIXED block, is kept by the handling of its VR, in Explicit and Implicit VR Little Endian, with the VR that (0008,0310) defines read where the file writes none: a number, a number string, and its creator are kept, a UID is replaced where written as UI, and text and a date are removed; without a declaration, the same block is removed; an attribute is removed where its VR is unknown or disputed, including by two definitions that disagree, in one item or in two, and with an agreeing item before or after, in Explicit and Implicit VR, or its value fails its VR’s check; a declared number is kept with as many values as the VM that (0008,0309) defines allows, fixed, open-ended, bounded, or with a stride, and otherwise with one, including where no item defines it, where the VM has no PS3.6 form, or where its stride is 0; an attribute that a reviewed rule keeps is removed where its block is UNSAFE, MIXED without it listed, or listed in Identifying Private Elements, where two items disagree, and where an item names its block with a status in lower case, as MIXED without its list, or with a listed element above 00FFH, and a reviewed rule still checks an attribute declared safe; a declaration for another group, a creator in another case or with a leading space, a reserved odd group, or an even group, keeps nothing; a declaration applies to its block in the items of a parsed private sequence, which it then keeps, while a (0008,0300) in such an item declares nothing and is removed; a sequence in a block marked UNSAFE is still parsed; end to end, the declared values are written, (0008,0300) is removed, no removed value is written, and the kept creator and number string are among the retained strings; and through the release gate, an instance whose declared block is a vendor’s of Table E.3.10-1 is released, while one whose declared block is another’s goes to QC review for the removed (0008,0302) alone (D-032). The conformance statement lists each rule that can retain an attribute, and no rule for text or removal, and describes how declarations are read, with nothing left pending under the Option; with Clean Descriptors too, it lists the 44 rules for text and describes how private text is cleaned, citing no decision. Under the Option with Clean Descriptors, private text written with its rule’s VR is given C, with its key, in Explicit VR Little Endian only, and removed without Clean Descriptors, in Implicit VR Little Endian, written as UN, or with more values than its VM allows; a reviewer’s decision keeps it with its creator, which leaves it out of the residual search and lists it as a retained string, or maps it, in whichever block the creator reserves; text that no decision covers is removed with a creator kept only for it, and listed in the QC pack by its key, while a creator kept for a number of its block stays; a kept value that echoes the patient is removed; text read as ISO 8859-1, and text that cannot be decoded as UTF-8, is removed without sequestering the instance; a parsed private sequence that holds only text keeps it, with both creators, where a reviewer keeps it, and is otherwise removed whole; declared text and text that TCIA’s dictionary keeps are cleaned as a rule’s are; a withheld instance leaves kept private text out of its collected values, but not text that no decision covers; the technique vocabulary keeps no private text; a key is refused for a group not open to private use, a creator empty, padded, or outside printable ISO 646 without a backslash, an element outside a block, or a VR other than text; the list saves and reopens private decisions as format 2, reads a list of format 1, and refuses one of format 1 with private text; the QC pack, of format 7, names each descriptor by its key or tag, and refuses another key; the release report counts one attribute in two blocks as one; and the decisions command records a decision on private text by its key. The shipped TCIA dictionary has the pinned length and SHA-256, with its attribution and licence; every row is read, with the counts of each disposition; a path is read through its sequences; a top-level attribute is found by creator, group, and element, ignoring only trailing spaces and NULs, with a creator in upper case matching only upper case; rows without a creator are read; an altered or missing copy is refused; and a file is rejected for each problem that its loader lists. Its rules keep a kept row’s attribute by the handling of its VR with a single value, or with the handling and VM of a reviewed rule for the same attribute and VR, remove another row’s, remove where two rows for one VR disagree, take the rule of the VR as written, and, where none is written, of the one VR other than OB, UN, or none, with none where there are several; give no rule to a row without a VR, a row below the top level, a creator outside printable ISO 646, a creator in another case, or another group; and ignore a creator’s padding, so that rows for two spellings of one creator meet as one attribute’s rows. A run that chooses it, in Explicit and Implicit VR Little Endian, keeps an attribute that only it keeps and removes one that only a reviewed rule keeps, reads a value without a VR by its rule’s VR, removes a value with more values than its VM allows or written as OB or with another VR, keeps one written as UN, still removes a block that (0008,0300) marks UNSAFE, and releases the instance; its method digest differs from the reviewed list’s and records the list, which is refused without the Option; its release report, in both forms, records
tcia; and its conformance statement gives the file’s SHA-256 and TCIA’s attribution and lists TCIA’s rules with TCIA’s names, while the default statement does neither. The command line and the library take the choice, and each refuses an unknown list, or TCIA’s without the Option, before anything is loaded or created. The edition check reports a change for a new edition not yet reviewed, a page that no longer links the pinned file or the licence, and a pinned file or shipped copy that differs from the pin, and a failure when the page or the file cannot be fetched or the page links to no edition, without reaching the network.
D-036: Technique descriptors kept by a reviewed vocabulary#
Decision.
Under Clean Descriptors, a value of a technique descriptor that the reviewed descriptors list has no decision on (D-009) is kept as it is, without review, where every word of it is in a reviewed vocabulary of technique, anatomy, and equipment words and it echoes no identifier of the instance, as the reviewed tier checks it. The list’s decisions take precedence, so a reviewer can empty or map a value that the vocabulary would keep. Every other value takes the list’s decision, or is not cleaned, as D-009 describes.
The technique descriptors are Series Description (0008,103E), Protocol Name (0018,1030), Sequence Name (0018,0024), Contrast/Bolus Agent (0018,0010), Contrast/Bolus Route (0018,1040), Derivation Description (0008,2111), Performed Procedure Step Description (0040,0254), Window Center & Width Explanation (0028,1055), Attenuation Correction Method (0054,1101), Scatter Correction Method (0054,1105), and Reconstruction Method (0054,1103). Study Description, Requested Procedure Description, comments, histories, diagnoses, and reasons are never kept by the vocabulary.
The vocabulary is the L2 file
technique_vocabulary.toml: groups of words, each with the reason its words describe technique, anatomy, or equipment rather than a person; units; the prefixes of vendors’ reconstruction kernels; and the Enumerated Values and Defined Terms that the pinned PS3.3 gives selected CS attributes of acquisition and reconstruction, with the body part terms of the pinned PS3.16 Annex L (D-032), each split at_and spaces. It leaves out excluded words, which name titles, sex, age, dates, records, and institutions, and every common personal name that is not a reviewed exception, each of which records why the word is chiefly technique or anatomy, such asHEADorDIXON. The common names are generated from the United States Census Bureau’s 1990 census name files, which are in the public domain: every given name, and every surname held by at least 0.001 percent of the population, 22,872 names in all. A group may not hold an excluded word or a common name that is not an exception, so that each such word is a recorded decision.A value is read as words, the runs of letters and digits between other characters, and kept only where it is printable ISO 646 without
^, which separates the components of a person’s name; holds no date or time, with any separators, including a clock time written with an hour unit, as in14H30,14HR 30MIN,9H 5MIN, or1430HRS, no run of five or more digits, and no digits that run on across separators from one word into the next to five or more; has at most one bare number, of at most three digits before its point and three after, other than two digits, a point, and two digits from10.00up, which could be a time; has every other word either a reconstruction kernel of a reviewed prefix, two digits, and at most one of the suffixes D, F, H, S, and U, as inB70f, or made of letter runs that are each a vocabulary word, or two or three vocabulary words of at least three letters joined, and digit runs of at most four digits before any point and three after that are not a year from 1900 to 2099, with at most one digit run in a word, so that512X512and14MIN30are held; has a single letter after digits, in a word or as the next word, only where it is a unit or theDof2D,3D, or4D, and no two single-letter words together, as initials are; holds no letter run that is a common name and not an exception, and noMR,MRS, orMSbefore an exception that is a common name; and has a vocabulary word of at least two letters. Words are matched without case. The rules are deterministic, so the same value is decided the same way in every run with the same vocabulary.The SHA-256 of the effective vocabulary, after terms, names, exceptions, and exclusions are applied, is an input to the method digest (D-024),
technique_vocabularyin its serialisation, ornullfor a run without a vocabulary, since the transform can be given another one or none, and the conformance statement describes the rules and the attributes, as PS3.15 E.3.5 requires the manner of cleaning to be described.Runs apply the vocabulary with the reviewed descriptors list, as D-009 describes.
The maintainer chose on 12 October 2026 to keep technique descriptors by a reviewed vocabulary as well as by reviewed values, over reviewed values only, stripping words outside the vocabulary from a value, or a trained entity recogniser.
Place names are not excluded by a bundled list. On 12 October 2026 the vocabulary was checked against GeoNames’ cities of at least 5,000 people, the countries, and the United States’ states, as the
geonamescache3.0.2 wheel on PyPI distributes them: 38 vocabulary words are also the name of such a place, all of them technique, anatomy, or function words, such asSUPERIOR,SPLIT, andCENTRAL, and they are kept. No place list is bundled: a value is kept only where its words are vocabulary words, so a place name is kept only where it is also a technique, anatomy, or equipment word, and a list would strike only such words while adding a licence that needs attribution.
Rationale. Under D-009 alone, no descriptor other than ROI Name is kept without pooled human review, and review cannot run on the MIDI-B benchmark, from which only counts, codes, and digests may leave CI, so the benchmark’s descriptor checks fail wherever a descriptor is expected to be kept. PS3.15 E.3.5 specifies what must be removed rather than a method, and its notes say that Series Description is usually written from a device’s protocol and rarely holds identifying information, and that a word can be both descriptive and identifying. Keeping only a whole value made of reviewed words, rather than stripping the other words, keeps nothing of a value that mixes technique with anything else, such as a name or an age, which goes to review. The residual risk is a value made only of vocabulary words that is also the name of a person not recorded in the instance, such as a Series Description of only
HAND, or a single word that reads as a kernel but is an initial, an age, and a sex, such asB45F; the common-name exclusion removes the common cases, the exceptions are recorded with their reasons, and the echo check holds a value that names a person of the instance. Joined words must each have at least three letters, since short words joined spell names:WOMBATisWO,MB, andAT. A trained recogniser was rejected because its output depends on a model and its version, so it cannot be described exactly in the conformance statement, and stripping because it keeps part of a name, asDr. HandbecomesHand.Tests. Technique values made of vocabulary words, with units, kernels, and numbers, are kept; values with a common name, a title before a named exception, a person name’s
^, an excluded word, a word outside the vocabulary, a date or time with any separators or with hour and minute units, every hour and minute of the day in the formTIME14HR30MIN, with four hour units, five separators, and padded and unpadded numbers, among them, two numbers in one word, a long, split, dotted, or second bare number, a year, initials, an age or sex letter after digits, or a character outside printable ISO 646, are not; Study Description, comments, and diagnoses are never kept by the vocabulary; joined words of fewer than three letters, and of four words, are not vocabulary; the vocabulary holds no common name that is not an exception and no excluded word, and holds terms of PS3.3 and Annex L; the file is refused where a group or the kernels hold an excluded word or an unreviewed common name, a kernel prefix is longer than two letters, an exception has no basis or is not a common name of the vocabulary, or an attribute is not a descriptor; the effective vocabulary’s digest changes with its words and itsreprshows none; cleaning keeps a vocabulary value, holds one that echoes an identifier, and applies a reviewer’s decision before the vocabulary; and the common-name list is refused where it is changed or is not a JSON object, and its generator keeps every given name and the surnames at or above the threshold, and refuses a source without the pinned digest.
D-037: Clean Pixel Data by detection and review#
Decision.
Under the Clean Pixel Data Option (PS3.15 E.3.1), the engine blacks out every region of text that a text finder finds in each frame of the top-level Pixel Data (7FE0,0010), native or compressed, whatever the text says, which E.3.1 Note 2 allows as “the most conservative approach of removing any and all burned in text”. The finder is the text detector of the
text-detectionextra, or any object with itsfindmethod and amethodthat describes what decides its regions; a transform takes one exactly when its policy selects the option. Its class and a copy of its description, read once when the transform is made, are an input to the method digest of every run under the option, so the markers and the release report identify the finder: for the text detector, its model’s SHA-256, the ONNX Runtime version and distributions, the NumPy and SciPy versions, its detection parameters, and its renderings (D-024). A finder that does not describe its method as a mapping that is not empty, or describes it with a value of a type that the digest does not define, is refused. Icons, in nested items, are removed by the Basic Profile.Beside the finder’s regions, the engine blacks out those of reviewed region rules, the rules of the maintainer’s choice of 12 October 2026 (“Rules plus detection”). A reviewer who has seen text that equipment burns in at the same place in every image of one kind, such as the header band of an ultrasound scanner, records a rule: rectangles to black out in every frame of every image whose SOP Class UID (0008,0016), Manufacturer (0008,0070), Manufacturer’s Model Name (0008,1090), Rows (0028,0010), and Columns (0028,0011) are the rule’s, the two names compared without their padding and with case, and Rows and Columns as integers. An instance that lacks one of them, or holds one in another form, such as several values, takes no rule. A private command records a rule from an attested QC pack (D-048): the regions given for one image, each of which must be one that the reviewer’s accepted or revised verdict approved for it in one of its frames, as the rule for the image’s kind, whose key it reads from the image’s source file, which must have the SHA-256 that the pack records; where the store already holds other regions for the key, it refuses them unless told to replace the rule’s regions or add to them. The rules are kept in a store for the site or project, a JSON file of format
pymedphys-deid-pixel-region-rules/1, held by the custodian as the reviewed-names list is (D-016), since manufacturers’ and model names together can identify a site’s equipment; each rectangle lies within its key’s Rows and Columns, and a store with a malformed or repeated key or rectangle, or a rectangle past them, is refused when it is read, naming no value. A transform takes rules only under the option, applies them as they stood when it was made, and blacks out the matching rule’s rectangles in every frame with the finder’s regions, with the same fill and the same check of the written value, never clipping one: a rectangle past the frame sequesters the instance asredaction-mismatch. A rule adds regions and removes none, and the instance it matches is held for review, astext-blacked-out, as every instance that the option cleans is. The QC pack lists a rule’s rectangles among the regions of every frame, and records which regions rules gave, so that a reviewer’s verdict takes them with the finder’s (D-048); the release report counts the regions of the instances that the run releases or holds without a verdict by what gave them; and the rules’ keyed digest is an input to the method digest (D-024).Each region is set to a constant stored fill: the frame’s smallest stored value for MONOCHROME2, its largest for MONOCHROME1, and zero for RGB. The fill erases the text’s pattern; how bright it is displayed depends on the Modality and VOI LUT attributes that are kept, which can invert it, so it is not always black, and a rule that guarantees a black display would need its own decision. In native Pixel Data, the new values are written in place of the old, byte for byte, in the source’s transfer syntax, so nothing else in Pixel Data changes; in Implicit VR Little Endian the writer accepts the new value although the dictionary gives Pixel Data OB or OW, since both hold the same bytes in little endian. Compressed Pixel Data, in a transfer syntax that encapsulates it, is decoded first, every frame, by the plugin pinned to its transfer syntax, in the decoding child for GDCM and pylibjpeg (Architecture item 2), and the finder searches the decoded frames. The new value is the decoded frames with any region or mask, written uncompressed in Explicit VR Little Endian, of VR OW above 8 bits and OB otherwise, with one byte of zero padding after frames of odd length; colour decoded from YBR_FULL, YBR_FULL_422, YBR_ICT, or YBR_RCT is written as RGB with Planar Configuration 0, and the Extended Offset Table (7FE0,0001), Extended Offset Table Lengths (7FE0,0002), and Encapsulated Pixel Data Value Total Length (7FE0,0003), which describe only encapsulated Pixel Data, are removed. It is so written even where the finder finds nothing, since the QC pack previews the file as written and a reviewer may add a region to it (D-048): kept compressed, its previews would be of the parent’s own decode rather than of the samples that a release writes. Lossy Image Compression (0028,2110), with its ratio and method, is kept as received. A frame without a region is left as it is. The file written is checked: pydicom must read the source’s stored values outside the regions and the fill inside them, or, for compressed Pixel Data, the decoded frames’ values, and every other byte of the value must be the source’s, or the decoded frames’ and their padding; otherwise the instance is sequestered as
redaction-mismatch.Only Pixel Data in whole bytes is cleaned: Bits Allocated 8, 16, or 32, High Bit one less than Bits Stored, and MONOCHROME1, MONOCHROME2, or 8-bit RGB, or, for compressed Pixel Data, also 8-bit YBR_FULL, YBR_FULL_422, YBR_ICT, or YBR_RCT, which decode to RGB. In native Pixel Data, the bit plane of each overlay that an overlay group without Overlay Data (60xx,3000) places above High Bit is cleared first, in the same write, and its group removed, as Clean Graphics does (D-041), since the previews do not show it and its graphics would otherwise stay. The bits above Bits Stored must then hold nothing but the value’s sign, since an overlay whose group is lost (PS3.3 Section C.9.2 before 2004), or anything else there, would stay. Float Pixel Data and Double Float Pixel Data, which a Parametric Map can hold (PS3.3 Sections C.7.6.24 and C.7.6.25), are cleaned where they are one sample of MONOCHROME2, uncompressed, in 32 or 64 bits as their element has them, and are the instance’s only pixel data: each frame’s regions are set to its smallest finite value, padding included, as an integer frame’s smallest stored value includes it, or to zero in a frame with none, so that the fill is a value the frame holds and no viewer reads it as missing, as many read not a number. They are written to the element that held them, of VR OF or OD, and checked bit for bit, so that a value that is not a number outside the regions keeps its payload and a zero its sign. The text finder searches each frame divided by the power of two at or above its largest finite magnitude, exactly for 32-bit values, so that its own arithmetic cannot overflow near the largest 64-bit values, with positive infinity above the frame’s largest finite value and negative infinity below its smallest, each by the finite values’ range, or by 1 where they have none, as the previews draw them, and not a number below negative infinity by as much again; padding is searched as it is, as in an integer frame. No overlay or defacer’s mask is written into them. Any other layout sequesters the instance as
uncleanable-pixel-data, before decoding for compressed Pixel Data. Compressed Pixel Data whose frames cannot be decoded for cleaning is sequestered asno-decoderorundecodable-pixel-data, as Architecture item 2 has it, asframe-mismatchwhere a decoder gives frames of another number, shape, sample type, or size than the attributes describe, and asuncleanable-pixel-datawhere it gives them in another colour space than expected.Every instance whose Pixel Data the option cleans is held for review, as
text-blacked-outwhere text was found andno-text-foundwhere none was, since the finder can miss faint, small, or noisy text, as the maintainer chose on 12 October 2026 (“Rules plus detection”). The QC pack lists its regions, by frame, and previews every frame of it at full resolution, since review must see each frame for text that the finder missed: as written, in grey for a monochrome frame without regions, and, for a frame with them, in colour beside the frame as received, which for compressed Pixel Data is its decoded frames, kept uncompressed for the pack, windowed together from it, with each region outlined in magenta along its own edge pixels, inside the region, so that the outline hides nothing beside it where text that a region only partly covered would show (D-016). Each of its frames is also given a review frame, which the redaction review app shows at its full depth, and which records the SOP Class UID that decides whether the reviewer must be shown every frame of the instance, as for every IOD at present, or only those with regions (D-059). A monochrome frame as written is also shown a second time, over its full range, from the smallest value to the largest of the frame as received, or as written where it has no regions, as the finder searches it, since the percentile window shows text at or near the extremes as white or black together with whatever else lies there, such as bone or air, and the full range keeps it apart. A cleaned instance claims the option, with DCM 113101 and Burned In Annotation (0028,0301) set to NO, only on a later run given a reviewer’s verdict on it (D-048). An instance whose source cannot be shown beside it, because the source cannot be read or decoded or differs in its frames’ shape, number, or colour, is listed as not previewed, assource-not-shown, rather than shown in part, and can be given no verdict, so it stays held. An instance without top-level pixel data claims the option in any run under it (D-048).The detector’s false positives on real images of the anatomy in scope are counted on the HaN-Seg data set’s 42 head and neck planning CTs and 42 T1-weighted MRs, under D-054’s rules for that data set: only a GitHub-hosted runner of the
Text Detector Checkworkflow (.github/workflows/pixel-text-validation.yml), started by hand, downloads it, and only counts, codes, digests, versions, and the detector’s method leave the runner. The check,pymedphys._dicom.deidentify.pixel_text_validation, run aspython -m pymedphys._dicom.deidentify.pixel_text_validation_command hansegonce for each image,CTandMR_T1, gives the detector, made as a run makes it, each slice along a volume’s third axis as a run gives it a frame, its values, rounded where they are not integers, as stored values, and clips each region to the slice as a run does; the renderings depend only on the stored values’ minimum, maximum, and differences, so CTs stored in Hounsfield units give the regions that they would with a rescale intercept. Its summary,pixel-text-validation.json, labelledpymedphys-deid-pixel-text-validation/2, and the same counts as CommonMark count the volumes by outcome, format, and plane, the slices and volumes by how many regions they give, and the regions by area as a share of the slice, shorter side, longer side over shorter, for CT, share of pixels above -900 HU, score margin, which is the highest mean probability that a rendering gave the region’s box less the box threshold, and the renderings that gave it, in fixed bins, and count the volumes, slices, and regions, with the regions by score margin and rendering, in each bin of the larger side of a slice and of the larger spacing within one, and give the detector’s method as the method digest takes it; they name no case and give no value. Inference, not measured: HaN-Seg’s images hold no burned-in text, so each region counted is one that a run would black out in error, over anatomy unless it is all air, and that a reviewer would have to clear. Worker processes, each with its own detector of one thread, find the regions that one process does. It claims no result. Its first run on main, on 26 October 2026, whose/1summary has no score margins and no counts by slice size or spacing, and whose counts the check’s guide records, found 33,183 regions in 7,162 of the CTs’ 7,581 slices, 22,659 of them with half or more of their pixels above -900 HU, and 953 regions in 719 of the MRs’ 3,613 slices, with a region in every volume of each image. Its rerun of 31 October 2026, at the commit that added the/2summary, whose counts the guide also records, gave the same counts, and found a region in 98.0% of the 6,449 slices of the 35 CTs whose slices are 1024 pixels or more on their larger side, against 74.3% of the 1,132 slices of the other 7 CTs and 19.9% of the MRs’ slices, all of 512 to under 640 pixels, with 48.1% of the CT regions kept at a box threshold of 0.7. Whether those false positives are acceptable for the option is the maintainer’s decision, not yet made.The option joins the options that the engine applies (D-011). No preset selects it, and it is not enabled (D-033).
The detector’s parameters, renderings, and model are evaluated and chosen as D-056 sets out, on images with and without burned-in text across the IODs in scope, against acceptance criteria set before tuning and confirmed once on held-out data; the detector so chosen becomes the default, and its held-out counts are recorded here.
Rationale. On synthetic phantoms the detector covered 96 to 99% of high-contrast strings of 7 to 14 pixels, but only 55 to 82% of faint ones, so review, not detection, is what lets an instance claim the option; region rules let a reviewer cover once, for every later image of a kind, the faint or small text that the finder misses there, and still leave each image to review, since a rule cannot know that a device has kept its text in place. Rows and Columns in a rule’s key let each rectangle be checked against the frame when the rule is recorded, so a rule is never clipped, for the reason that a reviewer’s region is not (D-048). Recording only regions that a verdict approved keeps a rule to what a reviewer has seen on a preview, and refuses a region misread from the pack, such as one with its coordinates transposed, which would otherwise black out the wrong place in every later image of the kind; reading the key from the source file that the pack’s SHA-256 binds records the kind of the image that the reviewer saw. Putting a rule’s rectangles in the pack’s regions lets the run given the verdicts black out exactly what the reviewer saw without reading the store again, which may have changed since; E.3.1 allows a process that “may require intervention of or approval by a human operator”. Writing into the existing value keeps the transfer syntax and needs no transcoding, and the byte comparison makes any other change visible. Compressed Pixel Data cannot be written into without encoding it again, which would put an encoder’s output in the file and, for a lossy transfer syntax, lose more, so its frames are written uncompressed, as decoded. Keeping the compressed value where the finder found nothing was rejected after review of the change: a reviewer can add a region to such an instance, and the release would then write the child’s decode, which no preview had shown, since the previews of a compressed file are the parent’s own decode. Decoded colour is written as RGB because pydicom converts YBR_FULL and YBR_FULL_422 to RGB, and the JPEG 2000 decoders reverse YBR_ICT’s and YBR_RCT’s component transformation, so only RGB describes the samples written. The decoder that writes those samples may be subverted by its codestream, which is why the instance is held for review, as every cleaned instance is, and released only through a verdict bound to its decoded frames (D-048). Holding every cleaned instance until a reviewer’s verdict is applied keeps the claim and Burned In Annotation NO tied to review, and releasing an instance whose text was found but whose pixels no one has seen was rejected for the same reason.
Tests. Regions set to the fill for MONOCHROME1, MONOCHROME2, signed values, and RGB in either planar configuration, with nothing else changed; each frame searched and cleaned with its own fill; regions clipped to the frame; Implicit VR Little Endian kept; Float and Double Float Pixel Data, in either native transfer syntax, cleaned in their own element with the frame’s smallest finite value, or zero where it has none, every other value’s bits kept, searched as finite values scaled by a power of two, and refused beside other pixel data, of another Bits Allocated, photometric interpretation, or number of samples, or too short, with any overlay or defacer’s mask; a not-a-number payload changed when written found; every other layout refused; compressed Pixel Data decoded in the child for JPEG 2000 and in process for RLE Lossless, with its regions blacked out and written uncompressed in Explicit VR Little Endian without its Extended Offset Table, frames of odd length padded, JPEG Baseline YBR_FULL_422 and JPEG 2000 YBR_RCT written as RGB, PALETTE COLOR refused before decoding, a child’s result of another colour space, sample type, shape, or size, or not of its form, refused, a decoder that fails refused, a written value or transfer syntax other than the plan’s found, and compressed Pixel Data without text written uncompressed, as decoded, and held; unused bits that hold more than the sign refused, unless an overlay group without Overlay Data places them, when its bit is cleared and nothing else in Pixel Data changed, its group removed, the regions blacked out in the same write, and the instance held; a written value that differs from the plan found, inside or outside a region; under the option, a CT image written blacked out, held for review, and without the code, an instance without pixel data written with it, a transform refused with a finder and without the option or without one and with it, or with a finder that does not describe its method in a form the digest defines, the finder’s class and description in the method digest that each instance and the release report record, and unchanged by a later change to the finder, and the release report counting held instances by reason; the QC pack listing each cleaned instance’s regions by frame, with its Rows and Columns, an entry without them or with a region past them refused, and previewing every frame, a frame with regions beside its source, through one window from the source, for MONOCHROME1, MONOCHROME2, signed values with a rescale, and RGB in either planar configuration, with the fill shown black in monochrome and nothing but the regions’ own edges outlined, a frame without regions in grey alone, a monochrome frame shown again over its full range, where text that the percentile window saturates together with bone stands apart, a source kept only for an instance with regions, an instance whose source cannot be shown listed as not previewed, and a pack refused unless each cleaned instance has a preview of each frame or is listed as not previewed; and a corpus run with a finder that marks a corner of every frame, which holds every image, lists each one’s regions, previews each of its frames at the expected size, and releases the rest; a rule’s rectangles blacked out in every frame with the finder’s regions, recorded as the rules’, each once, and never clipped, a rectangle past the frame refused, rules given only with a finder and only under the option, an image of another kind, by its Manufacturer’s case or its model, taking none, and a rule recorded after the transform is made not applied; the store read back as written and sorted, kept outside protected directories and readable only by its owner, refusing a malformed or repeated key, rule, or rectangle, or one past its key’s Rows or Columns, without quoting a value, its key’s
reprshowing no name, and its keyed digest the HMAC of its canonical form, independent of the order of its rules, and an input to the method digest that the markers and the release report record; the pack refusing a rule’s region that is not among the regions of every frame; the release report counting regions by what gave them, under the option only; and the command recording, from an attested pack, a region that a revised verdict added or that an accepted image’s pack listed, as the rule for the kind read from the source file, or from a copy of it, which a later run then applies to the kind’s other image and to no other kind, and refusing, with the store left as it was and no value or path quoted, a pack not attested or rejected, an image that no verdict accepts or revises, a region that the verdict did not approve, among them one transposed or one row short, a source file changed or unreadable, an image without a key, a store inside the pack or a protected directory, and other regions for a key that the store holds unless they replace or are added to the rule’s.
D-038: Retain Patient Characteristics#
Decision.
Under the Retain Patient Characteristics Option, the fourteen attributes that Table E.1-1 gives K are kept as they are read, wherever they are in the data set, and none is coarsened: Patient’s Age (0010,1010), Patient’s Sex (0010,0040), Patient’s Sex Neutered (0010,2203), Patient’s Size (0010,1020), Patient’s Weight (0010,1030), Ethnic Group (0010,2160), Ethnic Group Code Sequence (0010,2161), Ethnic Groups (0010,2162), Pregnancy Status (0010,21C0), Smoking Status (0010,21A0), Selector AS Value (0072,005F), and Sex Parameters for Clinical Use Category Sequence (0010,0043), Code Sequence (0010,0046), and Reference (0010,0047). The attributes in a kept sequence’s items take their own rules (D-022).
The five attributes of free text that the Option gives C, Allergies (0010,2110), Pre-Medication (0040,0012), Special Needs (0038,0050), Patient State (0038,0500), and Sex Parameters for Clinical Use Category Comment (0010,0042), are settled by the Option’s cleaner, which cleans the whole instance (D-034) and writes none of their values itself. It settles one with no value, or whose values hold nothing but spaces or NUL padding and backslashes, which is written with no value. It leaves out one with a value, or whose value could not be decoded, so that it stays pending. Without Clean Descriptors, there is no reviewed list, so such an attribute sequesters its instance.
Where the policy also selects Clean Descriptors, as
tps-importdoes, descriptor cleaning gives each value that the cleaner leaves pending the decision of the custodian’s reviewed descriptors list (D-009), as the maintainer decided on 25 October 2026. The list can decide on all five attributes, although Clean Descriptors gives C only to Allergies, Patient State, and the comment. A value that a reviewer kept, mapped, or emptied is written so, once what it would write is checked for echoes of the instance’s person names and patient identifiers, and a kept value is retained (D-027); the automatic tier of technique descriptors (D-036) does not apply. An element with a value that the list does not cover, or whose decision would echo an identifier, is written empty in the staged file, which is not released, and holds its instance for review, and the confidential QC pack lists its values so that a reviewer can record decisions for a later run; no user’s choice empties it instead. An element whose kept value would be beside a mapped or emptied one, or whose value could not be decoded, sequesters its instance.The conformance statement gives these five attributes and this method, so a policy whose only attributes given C, other than those that Clean Descriptors’ fallback settles, are the Option’s lists nothing as pending for them (PS3.15 E.3.7).
The measures of the patient’s body that the reviewed rules remove under every option, Patient’s Size Code Sequence (0010,1021), Patient’s Body Mass Index (0010,1022), Measured AP Dimension (0010,1023), and Measured Lateral Dimension (0010,1024), stay removed (D-022). A kept value is not searched for (D-027), and a kept text value is one of the retained strings that
public-releasereviews (D-017), as for any attribute kept. The indicators of a possibly disclosed body weight are still reported under the Option (D-015): they are read from the source, whatever the policy, and say no more than a kept Patient’s Weight does.
Rationale. E.3.7 retains “information about age, sex, height and weight and other characteristics present in the Attributes”, “as described in Table E.1-1”, for applications such as standardised uptake values and measures of body composition that need them, and requires the manner of cleaning retained attributes to be described in the conformance statement. Coarsening a kept value, such as an age above 89 years, was rejected: E.3.7 does not ask for it, the practice comes from regulations, after which no preset is named (D-014), and changing a value that the Option retains contradicts it (D-011). The five attributes given C hold free text written by people, such as a list of allergies or a note on the patient’s state, which can carry a name, a date, or a place. C asks for “values of similar meaning known not to contain identifying information” (Table E.1-1a), which no automatic method can know of free text, and D-009 retains no free-text value without pooled human review. Removing or emptying a value without review was rejected because it discards a characteristic that the Option retains, while the instance would still claim the Option (D-011), and writing the instance without the Option’s code because it would claim that the Basic Profile removed the characteristics that are kept (D-012). Letting the reviewed descriptors list decide these values, rather than always sequestering the instance, was chosen because a reviewer’s decision is the pooled human review that D-009 requires before free text is retained, and a reviewer who keeps or maps a value asserts what C asks, a value of similar meaning known not to contain identifying information; always sequestering would lose every
tps-importinstance with such a value, evenNONE. An unreviewed value holds its instance for review, rather than taking its action without Clean Descriptors as other descriptors do, because that action is the Option’s C, which cannot remove a characteristic that the Option retains. The custodian keeps one list of free-text decisions rather than one for each option, so its format changed to admit Pre-Medication and Special Needs. A reviewer’s decision to empty a value is accepted, as for a ROI Name, since it is a reviewed decision that the value cannot be retained safely. The technique vocabulary is not applied, since its words describe how an image was acquired, not a patient. An attribute with no value carries nothing, so sequestering its instance would discard data for no protection; and Sex Parameters for Clinical Use Category Comment is Type 2C in the Patient Study Module (PS3.3 Table C.7-4a), so it must be written with no value rather than removed where its condition holds. Allergies and Patient State are Type 3 in the Patient Study Module, which every IOD of the first supported release includes, and Pre-Medication and Special Needs are in no composite IOD’s modules; how many instances each holds is not yet measured. A cleaner that leaves out the values it cannot clean, rather than a list of attributes to hold kept apart from the registry, keeps each option’s handling of its attributes in one entry, which the statement describes.Tests. Every attribute that the Option gives C has the Option’s cleaner, and the Option gives the other fourteen K; an attribute with no value, or whose values hold only padding and separators, is written with no value, and one with any other value, such as
NONE, or one not decoded, is left out, stays pending in the edits, and sequesters its instance, at the top level or as the comment in Sex Parameters for Clinical Use Category Sequence; the Option keeps each kept attribute that a plan can carry, Ethnic Groups among them, with the Option’s code, while the Basic Profile removes or empties each one and the sequence; a kept Sex Parameters for Clinical Use Category Sequence keeps its Code Sequence and Reference and writes an empty comment with no value; under Clean Descriptors as well, empty values are written with no value and Patient’s Weight is kept, with both options’ codes; there, a value of each of the four attributes at the top level that the reviewed descriptors list keeps, maps, or empties is written so, with both codes, a kept value left out of the subject’s search and a mapped or emptied value’s source still searched for; an unreviewed value, at the top level or as the comment, holds its instance for review, written empty in the staged file, which the release gate holds for thedescriptorsstage’sunreviewed, and the QC pack’s material lists as not applied; a decision that would write a word of the patient’s name holds it forechoes identifier; a kept value beside a mapped one sequesters the instance, which leaves a Patient State that a reviewer keeps out of its collected values; a run’s release report counts the held instance at the stagedescriptors, counts no element as fallen back, and names no value; every one of the five attributes can be decided on, and a list of format 2 holding Pre-Medication is refused; without Clean Descriptors, a value still sequesters its instance; and the statement of the Option, alone and with Clean Descriptors, gives the five attributes and the method, and lists nothing as pending for them, and so doestps-import’s.
D-039: Modified Dates in the engine#
Decision.
Under Retain Longitudinal Temporal Information with Modified Dates, one reviewed cleaner of the whole instance (D-034) settles every attribute that Table E.1-1 or a supplementary rule gives C under the option: in 2026d, 184 attributes, every attribute with a temporal role but Patient’s Birth Date (0010,0030), Patient’s Birth Time (0010,0032), and GPS Time Stamp (0016,0077), which the option removes. Each value is modified by its attribute’s role (D-007): a subject-event or radiation-source DA value moves back by the subject’s offset (D-006); a DT value moves its date and keeps its time, once a value with its own UTC offset is in the instance’s local time with the nominal offset
+0000; a TM value is kept, and marked as retained, so the residual search leaves it out and records the drop (D-027); and Frame Origin Timestamp (0034,0007) moves its seconds. A device, vocabulary-version, or other value takes D’s constant for its VR, or the second where the source equals the first, as D writes it (D-021), so the residual search skips a source value equal to it (D-027). Timezone Offset From UTC (0008,0201) becomes+0000. Each value of a multi-valued attribute is modified on its own, an empty value stays empty, and an attribute with no value is written with none.The subject’s offset is the one its profile records (D-004), for the identity that the run resolves for the instance, its Patient ID with its issuer (D-005), so every instance of a subject in a run moves by the same offset. A new subject’s offset is derived from the key and the identity at first export. With the run-scoped key, the derivation is the subject’s profile, so no profile store is read or written, and runs move a subject by unrelated offsets, as they do UIDs and pseudonyms. Under a project key, the store records the offset at first export and every later run reads it back, so a later study keeps its intervals to the earlier ones.
The instance’s local time is its Timezone Offset From UTC, where it has one, and otherwise the offset of its earliest DT value that has one (D-007), among the values that the cleaner writes, so a value in a removed sequence has no say. Every valid Timezone Offset From UTC in the instance must have the same value. One that is not a valid offset says nothing of the local time, so it counts as absent, and it too becomes
+0000.The cleaner leaves pending, which sequesters the instance (D-034), any value that it cannot modify so: a DA value that is not a valid date, including the ACR-NEMA form YYYY.MM.DD; a DT value without a full date, which cannot move by whole weeks (D-006); a DT value at a leap second; one whose precision cannot express its conversion to local time; a value that would move before year 1; a valid Timezone Offset From UTC that differs from another in the instance; a value read in a VR that the pinned dictionary does not give its attribute, or that its role does not provide for; and every value that moves, in an instance without a subject’s identity, whose Patient’s Name and Patient ID are pending anyway (D-005).
The conformance statement gives the cleaner’s attributes and method, and, under Dates and times, how many of the attributes given C have each role, so it lists nothing about dates as not yet described (E.3.6).
Where two of a subject’s source dates differ by exactly its offset, such as a planning CT and a follow-up a year or more later, the shifted later date equals the earlier source date, and the residual search finds that source date in the shifted element (D-027). Such a finding does not withhold the file (
residual_shifts.py) where the run selects Modified Dates; the finding is of a date or datetime inside the data set, in an element of VR DA or DT whose attribute the option moves by the subject’s offset; a value of the element, or the date of a datetime value, equals a whole value of the finding’s source, or the date of a datetime; and every value of the element is a source value of the same element, pooled across the subject, moved back by whole weeks within the offset’s range with the same time of day. The same source value anywhere else still withholds the file. The maintainer chose this exemption over sending such files to review or keeping the search strict.
Rationale. One cleaner of the whole instance, rather than one per attribute, is needed because a value depends on others: a DT value’s conversion depends on the instance’s Timezone Offset From UTC or its other DT values, and every shifted value on the subject’s identity, which a cleaner of single values does not see. Keeping times follows D-006, since whole weeks keep the time of day: the date and time of an event move together, so the pair is modified, and the time alone identifies no one; marking a kept time as retained records it, rather than listing it as a value the search does not reach. Using D’s constants as the dummy values means one fixed value per VR, which differs from the source and is the same for every subject and run, so it discloses nothing of an offset, and the residual search already skips it. Sequestering a value that cannot be moved by whole weeks, rather than writing a dummy value for it, keeps every written subject-event value consistent with the others, and such values are rare: a DT value without a full date, a leap second, or an ACR-NEMA date. Requiring one Timezone Offset From UTC per instance avoids guessing which values a nested one applies to; one that is not a valid offset cannot be applied to any value, and replacing it discloses nothing of it, so the instance need not be held for it, as the synthetic corpus, which plants a text marker in every attribute, shows. A shifted date that equals another source date of its subject is the engine’s own value, and nothing in the file says that a source held it, so the match discloses only the coincidence, and nothing of the offset; a collection that holds one subject’s dates on most days of several years would meet it in most of its instances. Requiring every value of the element to be a whole-week shift of the element’s own source within the offset’s range keeps the exemption to values that the engine wrote, so one such value cannot clear another, and requiring the whole value keeps a date found elsewhere, or inside a longer value, withholding the file.
Tests. The cleaner covers exactly the attributes that the option gives C; subject dates move back by the derived whole weeks, keeping intervals and weekdays, including within multi-valued attributes and with empty values; times are kept and marked as retained; a radiation source’s decay interval to treatment is kept; DT values are put in local time, from Timezone Offset From UTC or, without it, the earliest DT value with an offset, and given
+0000; device, vocabulary-version, and other values take D’s constants, the second where the source equals the first, the same for every subject and key; Frame Origin Timestamp moves its seconds and keeps its nanoseconds; offsets are the same within a run, and differ between subjects and keys; an offset recorded in a project key’s profile is used even where the derivation now gives another, and a later run under the key moves the subject by it; each value that cannot be modified stays pending; differing time zone offsets leave the offsets and the DT values with their own offsets pending, while one that is not a valid offset counts as absent and becomes+0000; without a subject only the values that do not move are settled; a shifted date, or the date of a shifted datetime, including one of several values, equal to another instance’s source date is released, while the same date in an element that was not shifted, or under a run without Modified Dates, still withholds the file, and a date not moved by whole weeks in range, or in an element with another value that is not, is not exempt; an instance is written with every date modified, (0028,0303)MODIFIED, the option’s code, no source date in the file, and a release by the gate, and one with a date that cannot be modified is sequestered; a subject moves by one offset in every instance, other subjects and another key by others, so the synthetic corpus’s study and series dates that differ among a patient’s instances differ as before, as dcentvfy finds;tps-importmodifies its eleven device dates by role; and the statement of the option gives its method and role counts and lists nothing as not yet described.
D-040: Retain UIDs#
Decision.
Under the Retain UIDs Option, the engine applies Table E.1-1’s actions as it does any other option’s. The 55 UIDs that the table gives K under the option are kept wherever they occur, and its five sequences, Referenced Study Sequence (0008,1110), Referenced Performed Procedure Step Sequence (0008,1111), Referenced Patient Sequence (0008,1120), Referenced Image Sequence (0008,1140), and Source Image Sequence (0008,2112), are kept as containers whose items’ elements take their own rules. Every other UID is replaced with the run’s key (D-003): UID (0040,A124) and Digital Signature UID (0400,0100), which the table gives U under every option, and the instance UIDs that the table omits, such as Multi-frame Source SOP Instance UID (0008,1167), Volume Frame of Reference UID (0020,9312), and Referenced Fiducial UID (0070,031B), whose
instancerole gives U whatever the options.The engine still removes the four attributes of groups 0000, 0002, and 0004 that the table gives K under the option, Affected SOP Instance UID (0000,1000), Requested SOP Instance UID (0000,1001), Media Storage SOP Instance UID (0002,0003), and Referenced SOP Instance UID in File (0004,1511), as its own removals require. The File Meta Information that it writes (D-025) gives the kept SOP Instance UID as Media Storage SOP Instance UID, as PS3.10 Section 7.1 requires.
Output files are named by the keyed replacements of the kept Study, Series, and SOP Instance UIDs, so that under one key an instance has the same output name as under the Basic Profile, and no source UID is in a path (D-016). An instance whose kept identifier is not a single valid UID, which File Meta Information cannot hold, is sequestered as unnamed.
The reference graph’s second pass expects each input’s own UID at the identity and reference sites whose attributes the policy keeps, and its replacement at the others (D-026).
The residual search leaves out each UID that the policy keeps by Table E.1-1, where it is still collected: in an element removed with an enclosing sequence, or by the engine’s own removals (D-027). This holds for every option’s kept UIDs, so also for Device UID (0018,1002) and Manufacturer’s Device Class UID (0018,100B) under Retain Device Identity.
The markers claim the option for every instance written under it, since its actions alone satisfy it (D-012). The conformance statement says what keeping UIDs does to referential integrity, and the release report says that kept UIDs link each released instance to its source (PS3.15 E.3.9). No preset selects the option, so only a policy applied for validation can select it until per-run option sets are enabled.
A reference at an attribute that the table does not keep under the option, such as Multi-frame Source SOP Instance UID or a UID (0040,A124) that names an instance, is replaced while the UID that it names is kept, so it no longer resolves. Where both instances are in the run, the replaced reference’s source value is collected for the residual search, which finds it in the referenced instance’s kept SOP Instance UID and in every kept reference to it, so it withholds the referenced instance and each instance that keeps a reference to it, such as a plan whose Referenced Dose Sequence names a dose that frames were extracted from. The referring instance is released, and the second pass reports that its reference names an instance that was not written. On 12 October 2026 the maintainer chose this strict reading of the table over keeping the instance UIDs that it omits through a reviewed list, which would keep such references, but goes beyond E.3.9, which retains UIDs “as described in Table E.1-1”, and E.1.1, which requires the Basic Profile to protect every reference to a SOP Instance.
Rationale. Keeping exactly what Table E.1-1 lists under the option is the reading that conforms to both E.3.9 and E.1.1. Its cost falls on references that the table omits, which the CT, MR, PET, and RT objects in scope seldom hold, though no collection has measured how seldom. Naming files by keyed replacements keeps D-016’s guarantees: portable names within the 160-character bound, from no source value. Naming them by the kept UIDs was rejected, since a source UID of up to 64 characters breaks that bound and may not be valid, and a recipient reads the kept UIDs from the files themselves. Leaving a kept UID out of the search where its enclosing sequence is removed follows from the table, which keeps the attribute wherever it occurs, so finding its value elsewhere discloses nothing that the option does not; searching for it would withhold every subject whose removed sequences repeat a kept UID. Every UID that the option does not keep is still replaced under the run’s key, so runs share no replacement UIDs (D-004); the kept UIDs link runs and sources, which is the audit trail that E.3.9 provides the option for, at the risk that its first Note describes.
Tests. A policy that selects the option composes and is applied; it keeps the 55 UIDs and five sequences that the table lists, and gives U to UID (0040,A124), Digital Signature UID, and the instance UIDs that the table omits; under it, an RT Dose of frames extracted from a multi-frame RT Dose keeps its SOP Instance, Series Instance, Study Instance, and Frame of Reference UIDs and its references, while the Multi-frame Source SOP Instance UID in its Frame Extraction Sequence is replaced, its File Meta Information gives its kept SOP Instance UID, and it claims the option’s code; an RT Plan’s file is named as under the Basic Profile with the same key; an instance whose kept SOP Instance UID is not a valid UID is sequestered as unnamed; a kept UID in a removed sequence is left out of the residual search, while the instance’s other removed values are still searched for; a run of the synthetic collection under the option releases every instance with no finding from the second pass; with that extracted dose added, the run withholds the dose that it names and the plan that refers to that dose, and releases the extracted dose, whose references the second pass reports as naming instances that were not written; the second pass reports a replacement written where a kept UID was required, and an input’s UID written at a kept site is not reported as an original UID; and the conformance statement and the release report say what keeping UIDs means only when the option is selected.
D-041: Clean Graphics by the Basic Profile’s actions#
Decision.
The engine applies the Clean Graphics Option (PS3.15 E.3.3) without a cleaner of graphics: each of the four rows to which Table E.1-1 gives C under the option takes its Basic Profile action. Curve Data (50xx,xxxx), Overlay Data (60xx,3000), and Overlay Comments (60xx,4000) are removed (X), and removing Overlay Data removes every attribute of its overlay group where the IOD’s Overlay Plane Module is user-optional, as under the Basic Profile (D-020). Graphic Annotation Sequence (0070,0001) takes D, which removes it from every supported IOD but the softcopy Presentation States, since only the Presentation State IODs define it (Note 13 after Table E.1-1a); those make it Type 1, and a sequence has no dummy value, so a Presentation State that holds one is sequestered, as under the Basic Profile (D-010, D-021). The element rules give a masked row to which the policy gives C its Basic Profile action, as they already give a sequence (D-022); only Clean Graphics gives C to a masked row.
Every instance written under the option claims it, with DCM 113103, since E.3.3 specifies what the option removes, and Table E.1-1 gives the minimum actions, the reading that the maintainer chose for Clean Descriptors on 6 October 2026 (D-009). The conformance statement gives each of the four rows its Basic Profile action and says why, and lists nothing about graphics as not yet described.
Under the option, the bit plane of each overlay that an overlay group without Overlay Data (60xx,3000) places in unused bits of native Pixel Data is cleared, and the instance is released with the option’s code. PS3.3 before 2004 let an overlay lie in an unused bit plane of Pixel Data with one sample per pixel (Section C.9.2): its Overlay Bits Allocated (60xx,0100) is Bits Allocated and its Overlay Bit Position (60xx,0102) is the bit that holds it, so removing the group’s attributes alone would leave its graphics in the written file. Each bit of the plane, in every frame, is set as the value’s sign gives it, zero, or one where a signed value is negative, in the same in-place write as Clean Pixel Data’s redaction (D-037), and the written file is checked as a redaction is: every byte of Pixel Data must be the source’s but for those bits, and pydicom must read the source’s stored values from it. Every attribute of each such overlay group is then removed, as removing Overlay Data removes its group (D-020), since in signed Pixel Data the cleared bit gives each value’s sign, which a viewer that shows the embedded overlay would draw as its graphics. The pixel risk assessment still reports the source’s indicator for review (D-015).
An instance is sequestered as
overlay-in-pixel-datawhere an overlay group without Overlay Data places its overlay where it cannot be so cleared: its Overlay Bits Allocated is not Bits Allocated, its Overlay Bit Position is within Bits Stored, either cannot be read as one integer, or the instance has no Pixel Data, or Pixel Data that is compressed, is not monochrome in whole bytes as D-037 reads it, does not fit its frames, or has unused bits that hold more than the value’s sign once the planes are cleared, as another overlay whose group is lost would leave them.The option joins the options that the engine applies (D-011). No preset selects it.
Rationale. C allows a graphic to be kept once it is known to hold nothing identifying, but Table E.1-1’s minimum is the Basic Profile’s removal, so removing every overlay, curve, and graphic annotation meets the option while keeping none of them. Applying the Basic Profile’s action in the element rules, rather than leaving C pending for a fallback as descriptor cleaning does, means the plan, the edits, the residual search, and the statement all see the same removal as under the Basic Profile: no value is cleaned, so nothing new is written, and every instance of the synthetic corpus is written exactly as under the Basic Profile apart from its markers. Releasing an instance whose overlay may lie in Pixel Data with the option’s code was rejected, since it would claim a removal that did not happen. Releasing it without the code was rejected too: the run would drop a selected option for that instance without being asked, which D-011 does not allow, and only Clean Descriptors may go unsatisfied, besides Clean Pixel Data, which a held instance does not claim (D-012, D-048). Clearing the overlay’s bit plane meets the option without review: the bits lie above High Bit, so no stored value changes, and a cleared bit holds nothing that the stored value does not. Setting each bit as the value’s sign gives it, rather than to zero, keeps the unused bits of signed Pixel Data plain, so that Clean Pixel Data can still clean the instance. Clearing the whole plane, rather than only the overlay’s rows and columns from its origin, needs no reading of Overlay Origin or the overlay’s frames, and clears nothing that a viewer shows as the image. The group’s attributes are removed rather than kept as the Basic Profile keeps them, since they would still describe the cleared bit as an overlay, and in signed Pixel Data its bitmap is the image’s sign, which a viewer would draw over every negative value; setting the bits to zero instead was rejected, since the unused bits of a negative value would then no longer give its sign, and keeping them plain is what lets Clean Pixel Data verify that nothing else is there. The Overlay Plane Module is user-optional in each IOD that defines it, so removing the whole group leaves a valid instance, as under D-020. Clearing an overlay in compressed Pixel Data was rejected for now, since Clean Graphics would then have to decode the frames and write them uncompressed, which only Clean Pixel Data does (D-037, D-048), and one within Bits Stored would change stored values, which only review can accept. Keeping an overlay whose bitmap holds no text, which the text detector of Clean Pixel Data could decide with review, is later work.
Tests. Clean Graphics gives C to exactly these four rows; the rules give each row, and each element that it covers, its Basic Profile action, with and without Clean Descriptors, and no other option gives C to a masked row; under the option a CT Image’s overlay groups, curve groups, and Graphic Annotation Sequence are removed and the instance claims the option, as it claims both options with Clean Descriptors; an overlay in an unused bit of native Pixel Data has its bit cleared in every group without Overlay Data, as the sign gives it for a negative signed value, with nothing else in Pixel Data changed, its group removed, also from a signed image of mixed signs, and the instance claims the option; written Pixel Data that keeps the overlay’s bit or differs in another bit is found; an overlay group without Overlay Data whose overlay cannot be cleared, within Bits Stored, with Overlay Bits Allocated other than Bits Allocated, without an Overlay Bit Position or with two, beside another unused bit that is set, with Pixel Data that does not fit its frames, in compressed Pixel Data, or without Pixel Data, sequesters the instance as
overlay-in-pixel-data, even beside one with Overlay Data, and the release report knows the reason, while the Basic Profile releases the instance as received; every instance of the synthetic corpus, whose CT, MR, and PET images have Overlay Data, is written as under the Basic Profile apart from the markers, with the option’s code after the profile’s; and the statement gives each row its Basic Profile action and reason, names the sequestration, lists nothing as pending, claims the option without review, and lists it among the options that the engine applies.
D-042: Residual findings that a value an option keeps explains#
Decision.
A residual finding inside the data set (D-027) is not a reason to hold or withhold the file where a value that a selected option keeps explains it, in one of five ways:
Retained text. A text finding, which D-027 sends to QC review, is in an attribute that a selected option keeps and that the pinned dictionary gives only VRs of text (AE, CS, LO, LT, SH, ST, UC, or UT), and its source is a private data element or an attribute to which that option gives an action of its own. Under Retain Device Identity, this releases a station’s AE title, which the option cleans (D-034), or a vendor’s private copy of the station’s name, found in its kept Station Name (0008,1010), Device Serial Number (0018,1000), or Treatment Machine Name (300A,00B2); under Retain Institution Identity, a private copy of the institution’s name found in its kept Institution Name (0008,0080). Any other source, such as Institution Name or Institutional Department Name (0008,1040) found in a kept Station Name, or a private creator, stays under review.
Retained value. A finding of text, a date, or a datetime, from a source other than the element itself, equals a whole value of an attribute that a selected option keeps and that the pinned dictionary gives only VRs of dates, times, and datetimes. Under Full Dates, this releases a removed Patient’s Birth Date (0010,0030) equal to the kept Study Date (0008,0020). The same value found inside a longer kept value, other than as the date that begins a kept datetime, below, such as a removed datetime written to the minute and found at the start of a kept Acquisition DateTime (0008,002A), or in a value that no option keeps, still withholds the file. A source’s values are pooled across the subject, and the search records one finding of a source in each element, so the finding is explained only where every pooled value of its source that the search could find in the element equals a whole value of it: under Retain Device Identity, a kept Calibration DateTime (0018,1203) equal to one removed Acquisition DateTime (0008,002A) does not explain another, written to the minute, found whole at its start. In an attribute that the pinned dictionary gives only VR DA, a source value collected as DT counts as equal where its date, as YYYYMMDD, is a whole value of the element, since D-027 also looks for a datetime by its date and the text it then finds is the whole kept date, which holds no time: under Full Dates, this releases a vendor’s private scan or calibration datetime, removed with the other private attributes, found by its date in a kept Study Date, Series Date (0008,0021), Acquisition Date (0008,0022), Content Date (0008,0023), Instance Creation Date (0008,0012), or Performed Procedure Step Start Date (0040,0244) of the same day, where the date of every pooled value of the source that the search could find there equals a whole value of it. In an attribute that the pinned dictionary gives only VR DT, a source value collected as DA or DT that is a date as YYYYMMDD, or one collected as DT whose date, as YYYYMMDD, is, counts as equal where that date is the first eight characters of a whole value of the element, which PS3.5 makes the kept value’s date, since the text found there is then the kept date and holds none of the source’s time: under Full Dates, this releases GE PET images whose private datetimes of the
GEMS_PETD_01block, removed with the other private attributes, are found by their dates in the kept Radiopharmaceutical Start DateTime (0018,1078) or Radiopharmaceutical Stop DateTime (0018,1079), inside Radiopharmaceutical Information Sequence (0054,0016), of the same day, and a removed Patient’s Birth Date found at the start of the kept Acquisition DateTime of a scan made on the day of birth, where the date of every pooled value of the source that the search could find there begins a whole value of it. A datetime with a time found whole at the start of a longer kept datetime or inside it, a date found after the start of a kept value, a date or a datetime’s date found in another spelling, such as YYYY-MM-DD, in a kept date or datetime, and a removed date written in another form, such as ACR-NEMA’s YYYY.MM.DD, found there by its date, are still not explained. Each source value is read by the VR collected with it, as the search reads it, so a backslash in an ST, LT, or UT value is a character, and the value found across two kept times is not explained by either. Each is also looked for as the search encodes it, in each of its codecs and cases, so a value whose UTF-16LE bytes are inside a kept time is found there whatever the source’s character set, and is not explained.Unwritten UID. A UID finding equals a whole value of an attribute that a selected option keeps and that the pinned dictionary gives only VR UI, and every value of its source collected for the subject came from instances that the run does not write, as D-032’s unwritten code meaning reads them: an instance that the transform sequesters is not written, and one that the run withholds for another reason counts as written. Under Retain UIDs, this releases the instances of a study whose X-Ray Radiation Dose SR is sequestered, although the report’s removed scope of accumulation names the study by a UID (0040,A124), which Table E.1-1 gives U under every option, found in each instance’s kept Study Instance UID (0020,000D). A UID that a written instance also collected at the source, and one found inside a longer kept UID, in an element that no selected option keeps, such as kept text, or in the File Meta Information, still withholds the file.
Retained private creator. Under the Retain Safe Private Option, a text finding, which D-027 sends to QC review, is in a private creator, (gggg,0010) to (gggg,00FF) of a group open to private use, at the top level or in an item, whose whole written value, without trailing spaces and NULs, is a private creator that the run’s safe private list keeps in that group, compared exactly as the engine compares creators (D-035), and its source is a private creator or private data element, at any depth, or one of D-032’s six equipment attributes. A list keeps a creator in a group where one of its rules for that creator and group can retain a value: the reviewed rules, or TCIA’s Private Tag Dictionary where the run chooses it. With TCIA’s dictionary, which keeps
GEMS_PETD_01in group 0009 but not in 0011, 0013, 0017, or 0019, this releases the same block’s creator removed from another group or item, a private data element of another block, and Secondary Capture Device Manufacturer (0018,1016), each found in the kept creator. With either list, both of which keep the Philips PET creator in group 7053, it releases Secondary Capture Device Manufacturer found in that kept creator, which Table E.3.10-1 lists but which D-032’s vendor creator cannot explain, since the source is not a creator. A creator that the list keeps only in another group, or that differs in case, leading spaces, or any other character, explains nothing, nor does a kept data element of the block, and a finding from Institution Name (0008,0080), Station Name (0008,1010), Institutional Department Name (0008,1040), or any other source stays under review, so an in-house block named after the institution is still seen. The source’s pooled values need not all be the creator, since what is written where the finding is is the list’s own block name.Removed private UID. A UID finding equals a whole value of an attribute that a selected option keeps and that the pinned dictionary gives only VR UI, its source is a private data element, (gggg,1000) to (gggg,FFFF) of a group open to private use, at any depth, and every value of its source collected for the subject came from an instance whose output does not hold it: one whose edits remove the element, by X or with an enclosing sequence, or one that the run does not write. As for a retained value, the source’s values are pooled across the subject, so the finding is explained only where every pooled value of its source that the search could find in the element equals a whole value of it. Under Retain UIDs, this releases PET images whose removed private (0009,1013), which TCIA’s private tag dictionary calls FOR Identifier in GE’s
GEMS_PETD_01block, equals their kept Frame of Reference UID (0020,0052), and the CT images that share that frame of reference. A private UID that a written instance holds replaced, emptied, or still to clean, a source value found only inside a longer kept UID or that is another value of the source found there, one found in an element that no selected option keeps, such as kept text, or in the File Meta Information, and every standard UID source, including a reference that a written instance replaced or removed with its sequence, still withhold the file. The release report records it asremoved-uid.
A person name found in a value that a selected option keeps is never explained, but goes to QC review rather than withholding the file where the finding is inside the data set, at the top level or in an item, in an attribute that a selected option keeps and that the pinned dictionary gives only VRs of text (AE, CS, LO, LT, SH, ST, UC, or UT), whatever its source. A reviewer, who sees the kept value, then tells an institution’s or group’s own name from a person’s name typed into it, and the file is released only after that review. Under Retain Institution Identity, this reviews a Performing Physician’s Name (0008,1050), Referring Physician’s Name (0008,0090), or Operators’ Name (0008,1070) of which a word is also a word of the kept Institution Name (0008,0080), as in an institution named after a person; under Retain Patient Characteristics, a Patient’s Name (0010,0010) or a content item’s Person Name (0040,A123) whose family name equals the kept Ethnic Group (0010,2160). The same name found in a value that the Basic Profile keeps, such as a Beam Name, which the decision of 6 October 2026 covers (D-027), in a private element or creator, in a UID, in text that no selected option keeps, or outside the data set, still withholds the file, as does any other reason of the file that withholds it, such as a person name that could not be collected. The release gate gives the reason its own code,
residual-person-name-in-kept-text, which the release report counts among the instances held for review, and the QC pack lists the finding by its source and place.An option keeps an attribute where it gives K, by Table E.1-1 or by a reviewed supplementary rule (D-022), and the Basic Profile does not, and no other selected option gives it an action of its own other than K. Under
tps-import, the eleven device dates and times that Modified Dates modifies (D-007) are therefore not kept.The rules read the run’s options, which the transform records in each instance’s coverage of the residual search, rather than the tables alone, because the attributes that one option keeps can hold engine-written values under another: Modified Dates shifts the dates that Full Dates keeps, and a written date equal to its own source would mean that the shift failed. A value that an option writes by C, such as a shifted date or an AE-title token, therefore never explains a finding. A coverage with no options explains none. Under the Retain Safe Private Option, the coverage also records the safe private list that the run chose, since a creator that one list keeps can be one that the other removes; a coverage records a list only with the Option, a merge of a subject’s coverages keeps the list only where every coverage gives the same one, and a coverage with no list explains nothing by a kept creator.
Otherwise as D-032: a person name found anywhere other than in kept text as above, a UID that neither the third nor the fifth way explains, or a direct identifier found anywhere, and any value found outside the data set, still withholds the file; kept values are read from the written file’s bytes as ISO 646 text, and an element with any other byte explains nothing; and each exempted finding stays in the search, which the QC pack lists, with its exemption recorded in the release condition and counted in the release report.
This rule replaces the questions that D-034 (an AE title equal to a kept Station Name), Retain Institution Identity (private copies of kept institution values), and the Retain Longitudinal Temporal Information Options (a removed date equal to a kept date) left for the maintainer. It leaves Retain UIDs’ reading of a written instance unchanged: a reference that a written instance replaced, whose source UID equals a kept SOP Instance UID, still withholds the file (D-040).
The maintainer decided on 12 October 2026 to exempt findings that the option explains in both ways, over sending such date findings to review, exempting any removed value equal to a whole kept value from any source, or keeping the holds.
The maintainer decided on 26 October 2026, at 06:45:53 UTC, that a UID whose only sources are instances that the run does not write is explained, over withholding every instance of the subject that keeps it.
The maintainer decided on 2 November 2026, at 07:09:03 UTC, that text found in a private creator that the run keeps, whose value is a creator that the selected safe private list keeps, from a private element or one of D-032’s six equipment attributes, is explained, under
public-releasetoo, over explaining only a removed creator equal to the kept one or keeping the holds.The maintainer decided on 26 October 2026, at 06:45:53 UTC, that a UID whose only sources are instances that the run does not write is explained, over withholding every instance of the subject that keeps it.
The maintainer decided on 2 November 2026, at 07:09:17 UTC, that a removed private UID equal to a whole kept UID is explained, over sending such findings to QC review or keeping the holds.
The maintainer decided on 2 November 2026, at 08:33:26 UTC, that a removed datetime whose date equals a whole value of a kept date is explained, over keeping such instances withheld, after MIDI-B validation withheld GE PET and MR series under Full Dates whose private scan and calibration datetimes were found by their dates in kept dates of the same day.
The maintainer decided on 2 November 2026, at 08:34:35 UTC, that a person name found inside the data set in standard text that a selected option keeps goes to QC review and is never explained, over explaining it as the kept value’s own text or keeping the holds.
The maintainer decided on 9 November 2026 that a removed date or a removed datetime’s date found as the first eight characters of a datetime that the selected option keeps is explained, subject to the pooled-value rule. Findings that reveal a removed time, non-date sources, other date spellings, the kept value’s own source, and Modified Dates retain their existing hold or review outcomes.
Rationale. A Retain option keeps values that can identify, which is why
public-releaseomits Retain Device Identity and the Retain Longitudinal Temporal Information with Full Dates Option. A removed value found inside a value that the run’s policy keeps shows only that the removed text is in a value released anyway, so it reveals nothing that the kept value does not, and the kept value is released whether or not a removed copy of it exists. Holding such files puts review effort on findings that the policy has already decided: a station’s AE title commonly equals its Station Name, vendors repeat the station’s and institution’s names in private elements, and dates, of which a year has only 366, often coincide. The two ways are each limited to where the coincidence explains the finding. For text, the source must be of the option’s own kind or a private copy, so an institution’s name found in a kept Station Name under Retain Device Identity, which shows that the station’s name holds what the option does not keep, still goes to review. For dates and times, the finding must be a whole kept value, so that a kept value whose part matches is still withheld. A datetime found by its date in a kept date meets that limit from the kept side: what the search found is the whole kept date, a conformant DA holds only its eight digits, and the datetime’s time is not in it, while the whole datetime, found anywhere, is a finding of its own; so the finding discloses only the kept date, as a removed date equal to it would. A date found as the first eight characters of a kept datetime meets the same limit: PS3.5 makes those characters the kept value’s date, so what the search found is the whole kept date, which the option releases anyway, and the source’s time is not in it. A datetime with a time found whole at the start of a longer kept datetime, or a date found after its start, still withholds, because there the found text is part of the kept time or of a longer kept value. Releasing a removed datetime only where its date is a whole kept date, and keeping it withheld where its date begins a kept datetime, would hold files for findings that disclose no more: in the MIDI-B workflow’s run 42229019914 of the Test subset, Full Dates alone withheld 545 GE PET instances that the Basic Profile released, each only for private datetimes of theGEMS_PETD_01block found by their dates in the kept Radiopharmaceutical Start DateTime and Stop DateTime of the same day. UIDs are otherwise excluded because a UID found in a kept UID shows a reference that was replaced while its target was kept, which Retain UIDs must make consistent rather than release. That holds only where an instance holding the replaced reference is released: where only instances that the run does not write held the UID, nothing inconsistent is released, and the option releases the UID where it is found anyway, so withholding every instance of a study for a report that is itself withheld protects nothing. Nor is anything inconsistent released where the UID’s source is a vendor’s private copy that every instance which held it removed: no element of the output refers through the copy, so there is no replaced reference to make consistent, and the option releases the kept UID anyway. Only a private source qualifies, because the engine reads a standard UID’s references, which D-040 decides, while a private copy is opaque to it and is removed by the Basic Profile; and a copy that any written instance holds replaced, as a reviewed rule’s or another list’s handling of a private UID could leave it, still withholds, since that instance’s output then refers through it. The removed private UID needs a whole kept value and every other value of the source that could be found there to be one too, as for dates, so that a private value of which the kept UID is only a part is not released by the coincidence. The unwritten UID needs a whole kept value and every value of the source from such instances, so that a written instance’s replaced reference still withholds its targets, and a UID in text, which no option keeps as a UID, still withholds the file. Exempting a removed value equal to any kept value, from any source, was rejected because it would release an institution’s name typed as a station’s name without review and the Retain UIDs case; sending date findings to review instead of releasing them, because a reviewer could only confirm a coincidence; and keeping the holds, because every Retain option would then hold most files for findings that the policy explains. A private creator that the Retain Safe Private Option keeps holds only the block name that the run’s list matched, so a removed value found in it is that vendor text, which the run releases anyway: in a MIDI-B run of the Validation subset started on 1 November 2026 with TCIA’s dictionary, the Option released 9,878 instances against the Basic Profile’s 21,271, and the other 11,393 were held for text found in kept private creators, at places where the Basic Profile keeps nothing, from the same block’s creator removed from another group or item, a private data element, or Secondary Capture Device Manufacturer, since D-032’s vendor creator needs a creator that Table E.3.10-1 lists, and that table lists none in group 0009. The way is limited to private and equipment sources because those are vendor text by their kind, while an institution’s or station’s name found in a kept creator would show that the list keeps a block named after the site, which a reviewer should see. Explaining only a removed creator equal to the kept one was rejected because it would leave the private data elements and device names that vendors repeat in their own creators under review, which reveal no more; and keeping the holds, because the Option’s evidence would then exclude most of the blocks that TCIA’s list keeps. For the removed private UID, sending such findings to QC review instead was rejected, because a reviewer could only confirm a coincidence, as for dates; and keeping the holds, because Retain UIDs would then withhold every PET series with such a copy, and the CT series that share its frame of reference, for a copy that the output does not hold. A person name is searched whole, by its component groups, by each of its names and each word of them, and run together, in each form of at least 4 characters (D-027), so a name word that is also a word of a kept institution’s name, or a surname equal to a kept ethnic group, withholds the file, and nothing could release it. In the same MIDI-B run, Retain Institution Identity withheld 4,163 PET instances of the Validation subset for that alone, 20% of the Basic Profile’s 21,271 releases, for a Performing Physician’s Name in the kept Institution Name in 4,095 and a Referring Physician’s Name there in 68, and 47 PET instances of the Test subset for an Operators’ Name there; and Retain Patient Characteristics withheld 55 MR instances of the Test subset for a Patient’s Name and a Person Name found in the kept Ethnic Group. The counts cannot say whether a kept value is the institution’s or group’s own name or a person’s name typed into it, and the answer key checks none of the Ethnic Group values in those 55, which suggests, as an inference, that the benchmark treats them as identifying rather than as an ethnic group. A reviewer who sees the value can tell, so review neither releases a name unseen nor loses every file of an institution named after a person. Explaining such a finding as the other ways do was rejected because it would release, without review, a person’s name planted in a kept value; and keeping the holds, because no review could then release a file of an institution named after a person. The route is limited to standard text that a selected option keeps, where the policy has already decided to release the value and only whether it is that kind of value or a person’s name is in doubt, which the attribute’s meaning lets a reviewer judge. A name in a value that the Basic Profile keeps, such as a Beam Name, stays under the decision of 6 October 2026, which first measures such findings with a list of surnames; a name in a private element or creator that the safe private list keeps would mean that the list keeps a block that holds a name, which reviewing one file does not correct; and a name in a UID, in text that no option keeps, or outside the data set is in no value that the policy releases.Tests. An option keeps what it gives K and the Basic Profile does not, including supplementary rules’ attributes and not what it cleans, and
tps-importkeeps none of the device dates that Modified Dates modifies, while Full Dates keeps the Study Date that Modified Dates shifts; a coverage carries its options through a merge, and rejects them other than as a tuple of strings. Under Retain Device Identity, a kept Station Name, Device Serial Number, or Treatment Machine Name holding a value found from an AE title that the option cleans, from a private data element, or from another attribute that the option keeps is released, with the exemption recorded, and under Retain Institution Identity a private copy of the institution’s name found in its kept Institution Name; the same finding with no option, one found from Institution Name, Institutional Department Name, or a private creator, and one in other kept text or in a value with a byte outside ISO 646, go to review; and a person name found in kept text goes to review, with nothing explained, but withholds the file with no option. A removed date equal to a kept Study Date under Full Dates is released, but withheld with no option or under Modified Dates, or from the Study Date itself; a removed date, or a removed datetime’s date, or a datetime written to the day, that begins a kept Acquisition DateTime or Radiopharmaceutical Start DateTime under Full Dates, with or without fractional seconds or an offset from UTC, or a kept Calibration DateTime under Retain Device Identity, is released with the exemption recorded, also where another pooled value of the source, of another day, is not in the element, and a PET image whose removedGEMS_PETD_01datetimes are of its kept Radiopharmaceutical Start DateTime’s day is released under Full Dates with each of those findings exempt; the same date or datetime with no option or under Modified Dates, a removed datetime with a time found whole at the start of a longer kept datetime or inside it, a date found after the start of a kept value, a date in another spelling in a kept datetime, an ACR-NEMA date found by its date, and the kept datetime’s own source still withhold, and removed text that begins a kept datetime goes to review; a removed private datetime whose date equals a kept Study Date under Full Dates, or a kept Date of Last Calibration (0018,1200), one of its values or its only one, under Retain Device Identity, is released with the exemption recorded, also where another pooled value of the source, of another day, is not in the element, and an RT Plan whose private scan datetime is of its kept Study Date’s day is released under Full Dates with that one finding exempt; the same datetime is withheld with no option or under Modified Dates, or by its date in another spelling in a kept date, and a removed ACR-NEMA date found by its date in a kept date is still withheld; and a removed UID equal to a kept SOP Instance UID under Retain UIDs still withholds. Under Retain Device Identity, an RT Plan whose Station AE Title equals its Station Name, with a private copy of the name, is released with both findings exempt, and one whose Station Name holds its removed Institution Name is held for review. Under Retain UIDs, CT slices whose Study Instance UID a sequestered X-Ray Radiation Dose SR names in its removed scope of accumulation are released, with each finding exempted as an unwritten UID and counted in the release report, while the same UID also collected from a written instance, found in an element that no option keeps or inside a longer kept UID, found in the File Meta Information, or found with no option, still withholds; and a merge of coverages keeps a value unwritten only where every coverage that collected it gives it as unwritten, and refuses an unwritten value that is not collected. Under Retain Safe Private, with either list, a removed creator of another group or item, a private data element, and each of the six equipment attributes found in a creator that the list keeps, at the top level or in an item, is released with the exemption recorded and counted in the release report, also where another pooled value of the source is not the creator; the same finding with no option, with no list, or with a list that does not keep the creator, from Institution Name, Station Name, Institutional Department Name, Series Description, or Private Creator Reference, or found in a creator that the list keeps only in another group, in another case, with a leading space, more text, or two values, in a kept data element of the block, or in standard text, goes to review; a person name, a UID, or a direct identifier found in a kept creator still withholds; a coverage records its list only as a SafePrivateList and with the Option, and a merge keeps it only where every coverage gives the same one; a run under the Option records its list in each coverage and, with TCIA’s dictionary, releases a CT slice whose keptGEMS_PETD_01creator holds the creator removed from group 0011, and, with either list, one whose kept Philips PET creator holds its removed Secondary Capture Device Manufacturer, and a run without it records none. Under Retain UIDs, CT slices whose removed private (0009,1013) copies their kept Frame of Reference UID are released, with each finding exempted as a removed UID and counted in the release report, and the private copy at the top level or nested in a private sequence is explained, as is one beside another removed value of the source on another frame of reference; the same copy that a written instance holds replaced, alone or beside one that removed it, another value of the source that a written instance replaced, another removed value found inside the kept UID but not the whole of it, the copy found with no option, inside a longer kept UID, in kept text, in a UID that no option keeps, or in the File Meta Information, a standard source removed with its sequence, a private creator’s slot, and a reference that a written instance replaced, whose source UID equals a kept SOP Instance UID, still withhold; the transform gives a value whose element it removes as removed and one that it replaces as not; and a merge of coverages keeps a value removed only where every coverage that collected it gives it as removed, an instance that is not written gives every value it collected as removed, and a coverage refuses a removed value that is not collected. Only standard text that a selected option keeps is kept text: Institution Name and Institution Address under Retain Institution Identity, Ethnic Group and Patient’s Sex under Retain Patient Characteristics, and Station Name under Retain Device Identity are, and Institution Name with no option or another, Beam Name, a private data element, and Patient’s Age, of VR AS, are not. Under Retain Institution Identity, a Performing Physician’s Name, Referring Physician’s Name, or Operators’ Name found in the kept Institution Name, at the top level or in Contributing Equipment Sequence, goes to QC review with the reasonresidual-person-name-in-kept-text, its source and place recorded, nothing explained, and the finding kept in the search, as does a name from a private source collected as PN, and a coverage merged across the subject; under Retain Patient Characteristics, a Patient’s Name or a content item’s Person Name equal to the kept Ethnic Group goes to QC review in the same way. The same name in an Institution Name with no option, under Retain Device Identity, Retain Patient Characteristics, or Retain Safe Private, in a Beam Name, in a private data element that Retain Safe Private keeps, or in a Station Name that the selected options do not keep still withholds; it withholds where it is also found in the File Meta Information or in a Study Description that no option keeps, and where a person name could not be collected; and a Patient ID, a UID, or a date found in the kept Institution Name still withholds. A run under Retain Institution Identity holds for review a CT slice whose kept Institution Name is named after its removed Performing Physician’s Name, which the release report counts under the code, and a run under the Basic Profile releases it. The conformance statement describes the code as one by which the release gate holds an instance for review.
D-043: Full Dates in the engine#
Decision.
The engine applies Retain Longitudinal Temporal Information with Full Dates (PS3.15 E.3.6), which a custom option set can select and no preset does. It keeps every date, time, and datetime that Table E.1-1 gives K under the option, 169 attributes in 2026d, and the 15 that the table omits and the supplementary rules give K under it (D-023), with Timezone Offset From UTC (0008,0201) among them, so no value is shifted or otherwise modified. Patient’s Birth Date (0010,0030), Patient’s Birth Time (0010,0032), and GPS Time Stamp (0016,0077), to which the option gives no action, keep their Basic Profile actions. It cannot be selected with Modified Dates, which E.3.6 makes mutually exclusive with it.
K needs no cleaner (D-034). The markers add the option’s code, DCM 113106, and set Longitudinal Temporal Information Modified (0028,0303) to UNMODIFIED, unless MODIFIED or REMOVED is already present from an earlier run (D-012).
Kept dates stay in the residual search (D-027), and a finding in one is explained as D-042 says. Where a source value that the policy removes or replaces equals the whole of a kept date, such as a Patient’s Birth Date equal to the Study Date of a scan made on the day of birth, or a date in an item of a sequence that the policy removes, such as Request Attributes Sequence (0040,0275), equal to it, the search finds it in the kept element, and the kept value explains it, so the instance is released with the finding exempt; found inside a longer kept value, such as a removed datetime written to the minute at the start of a kept datetime, it still withholds the instance. A removed datetime, such as a vendor’s private scan time, whose date equals a kept date, and a removed date, or a removed datetime’s date, that is the date that begins a kept datetime, such as Radiopharmaceutical Start DateTime (0018,1078), are explained in the same way, as D-042 says.
Rationale. E.3.6 requires the dates and times that Table E.1-1 lists to be retained and the marker to say UNMODIFIED, which the composed actions and the markers already give, so the option needs only to be accepted by the engine. Such a finding discloses nothing that the option does not already keep: the output holds only the kept date, and nothing in it says that a removed attribute had the same value. The exemption is D-042’s, which the maintainer decided for every Retain option, so the option adds none of its own.
Tests. Under Full Dates, an instance keeps every date, time, and datetime that the option keeps, and its Timezone Offset From UTC, and none is shifted; Patient’s Birth Date and Patient’s Birth Time are removed or emptied as under the Basic Profile; the markers carry DCM 113106 and UNMODIFIED, and a MODIFIED or REMOVED already present is kept; the gate releases the instance; an instance whose Patient’s Birth Date, or a date in an item of its Request Attributes Sequence, equals its Study Date is released, with one residual date located in the kept element and exempt as a retained value, and so is one whose private datetime is of its Study Date’s day; Full Dates and Modified Dates together are rejected; and the conformance statement says that no date or time is modified, counts the attributes kept, says that a removed value equal to a whole kept one, or a removed datetime whose date equals a whole kept date, is explained by it and one inside a longer kept value withholds the instance, gives UNMODIFIED, and lists nothing as not yet described.
D-044: Retain Institution Identity#
Decision.
The engine applies Retain Institution Identity, one of the options in Scope, as the maintainer asked on 12 October 2026 for every option of PS3.15 Annex E, alone or with any other option that it applies. No preset selects it, and nothing conflicts with it: the Option gives K only, and no other option gives those attributes another action than the Basic Profile’s.
The ten attributes that Table E.1-1 gives K under the Option are kept as read, wherever they are kept in the data set, with the Option’s code: Institution Name (0008,0080), Institution Address (0008,0081), Institution Code Sequence (0008,0082), Institutional Department Name (0008,1040), Institutional Department Type Code Sequence (0008,1041), Clinical Trial Site ID (0012,0030), Clinical Trial Site Name (0012,0031), Clinical Trial Coordinating Center Name (0012,0060), Clinical Trial Protocol Ethics Committee Name (0012,0081), and Source of Previous Values (0400,0564). The Option gives no attribute C, so it needs no cleaner (D-034). An attribute in the items of a sequence that the policy removes goes with it: Source of Previous Values is defined only in Original Attributes Sequence (0400,0561), and Institution Name, Institution Address, and Institutional Department Name are also defined in the items of the sequences that identify people, such as Operator Identification Sequence (0008,1072), and of ROI Creator Sequence (3006,004D), all of which are removed under every option.
Clinical Trial Protocol Ethics Committee Name is removed under the Option too, as D-020 decided, since its Type 1C condition needs Clinical Trial Protocol Ethics Committee Approval Number (0012,0082), which Table E.1-1 removes under every option. The instance still claims the Option, and the conformance statement lists the name as removed wherever it is.
The attributes that Table E.1-1 omits and that name other organisations, such as Coding Scheme Responsible Organization (0008,0116), Strain Source (0010,0217), Algorithm Source (0024,0202), and the issuers of identifiers, stay removed under every option (D-022).
A kept value is not searched for (D-027), and a kept text value is one of the retained strings that
public-releasereviews (D-017), as for any attribute kept.The residual search collects the values of removed attributes and looks for them in what is written (D-027). Under the Option, such a value can also be part of a kept institution value: a private element that names the site, a Station Name that repeats the institution’s name, or a Referring Physician’s Address in the same hospital as Institution Address. The maintainer decided on 12 October 2026 that one rule, D-042, settles such findings for every Retain option: a finding is released where the Option explains it, because its removed value came from a private element or from one of the Option’s own attributes, and any other, such as an institution’s name in a removed Station Name, still goes to QC review. A person name found in a kept institution value goes to QC review too, and is never explained (D-042); UIDs and direct identifiers, and person names found anywhere else, still withhold the file.
Rationale. E.3.11 retains “information about the identity of the institution in the Attributes”, “as described in Table E.1-1”, for applications that need the institution to analyse or interpret images, or to keep a record of it for regulatory or registry purposes. The Option keeps what the Basic Profile removes and adds nothing that conflicts with another option, so it needs only the engine’s existing rules, the option’s code (D-012), and its place in Scope. Clinical Trial Protocol Ethics Committee Name stays removed because keeping it, without the approval number that every option removes, would make every instance that has it invalid, as
dciodvfyreports (D-030), and E.1.1’s Note makes keeping the IOD intact the de-identifier’s responsibility. The Option’s own rows make that one retention impossible in valid output, so the instance still claims the Option; sequestering every instance with the name was rejected, since it would discard instances that the Option can otherwise de-identify, and leaving out the Option’s code was rejected because the instance would then claim that the Basic Profile removed the institution attributes that are kept (D-012). The organisations that the reviewed rules remove are not the institution where the acquisition was performed, which E.3.11 describes, and E.1.1 lets the de-identifier protect attributes beyond Table E.1-1, so they stay removed. No exemption is built here, since one rule for every Retain option (D-042) keeps the residual search’s exemptions in one place.Tests. The Option is a target option that the engine applies, alone and with each other option it applies; under it, an RT Plan keeps Institution Name, Institution Address, Institutional Department Name, Institution Code Sequence, Institutional Department Type Code Sequence, the clinical trial site’s ID and name, and the coordinating centre’s name, and Institution Name in an item of Contributing Equipment Sequence, with the Option’s code, while the Basic Profile removes, empties, or replaces each one; Clinical Trial Protocol Ethics Committee Name is removed, with its approval number, while the instance claims the Option; Source of Previous Values goes with Original Attributes Sequence; Coding Scheme Responsible Organization is removed; and the statement of the Option lists nothing as pending, lists the ten attributes as kept, and lists the ethics committee’s name as removed wherever it is, with the reason D-020 gives.
D-046: Clean Recognizable Visual Features by face review#
Decision.
The engine applies the Clean Recognizable Visual Features Option (PS3.15 E.3.2) by face review: it claims the option only for an instance that cannot show a face, or in which a reviewer found no recognisable face, and holds every other instance that can show one for review, so that it is never released. The maintainer chose this on 12 October 2026, from the options of reviewing first and of a second run given the verdicts. Removing the face block from CT (D-050) changes what a defaced instance holds, never whether it claims the option.
A run under the option is given the QC pack of an earlier run of the same files, attested with face verdicts (D-016, D-017). The attestation must bind the pack, the pack every preview, and both must be of their formats; a pack that is not attested, or whose attestation’s outcome is rejected, since a reviewer who rejected the pack has not cleared what it holds, or a verdict that names a series that the pack does not list, is refused when the verdicts are read, before the run starts. Each series marked absent gives the SHA-256 of each of its source files, and each series marked present likewise. The library’s
deidentifytakes that pack asface_review, which a run under the option needs, and reads its verdicts before what ROI Names and descriptors are cleaned with; a face review given without the option is refused before it is read, and a run under the option without one, or with one that cannot be used, stops before it starts, with a message that names no path. The command takes the pack as--face-review DIRECTORYin the same way: it applies exactly where the run’s policy selects the option, and is an argument error otherwise (D-033), and a run under the option without one, or with one that cannot be used, could not start.An instance can show a face where it holds Pixel Data (7FE0,0010), Float Pixel Data (7FE0,0008), or Double Float Pixel Data (7FE0,0009), or is an RT Structure Set, whose contours can trace the skin surface (D-015), or holds a deformable registration’s grid, Vector Grid Data (0064,0009) in an item of Deformable Registration Grid Sequence (0064,0005), which gives a displacement at each point of a grid over the patient and can follow the outline of the face; a Deformable Registration Sequence (0064,0002) whose items cannot be read counts as holding one. Such an instance satisfies the option only where the SHA-256 of its source file, as the run’s first pass read it, is that of a file of a series marked absent, and the SHA-256 of the pixel data that the run writes of it is that of the pixel data that the reviewed run wrote of that file, which the pack records only where its previews show every frame of them, for an RT Dose only its dose-levels previews and for a Segmentation only its segments sheet (D-016, D-017), and the pack showed at least as many frames of them as the run writes, counted for an RT Dose from its dose-levels previews alone and for a Segmentation from its segments sheet alone, as, for an RT Structure Set, is the SHA-256 of the contours that it writes, which the pack records only where its contour sheet shows them (D-017), and, for an instance that holds a grid, the SHA-256 of the grids that it writes, which the pack records only where a grid sheet of each kind shows each of them (D-017). The pixel data’s digest is of the value of each of Float Pixel Data, Double Float Pixel Data, and Pixel Data that the data set holds, in that order, each after its tag and length, a value of odd length being taken with its pad byte. The contours’ digest is of the number of items of ROI Contour Sequence, then, for each in order, the number of its contours, and, for each contour in order, the length and UTF-8 bytes of its Contour Geometric Type, and, for each of its Contour Data, Contour Offset Vector, and Contour Slab Thickness, the number of its values and each value as a big-endian 64-bit float, each count and length a big-endian 64-bit unsigned integer, and a data set without a contour gives the digest of no items, so it changes with any contour that the run cuts, and not with how a value is written. The grids’ digest is of the number of grids, every item of each Deformable Registration Grid Sequence in each item of the Deformable Registration Sequence, in order, then, for each in order, for each of its Image Orientation (Patient), Image Position (Patient), Grid Dimensions, and Grid Resolution, the number of its values and each value as a big-endian 64-bit float, and the length and value field of its Vector Grid Data, with the pad byte of a value of odd length, each count and length a big-endian 64-bit unsigned integer, so it changes with how any grid is placed or displaced, and a data set without a grid gives the digest of none, which needs no grid sheet. Otherwise it is written without the option’s markers and held for review, at the stage
visual-features, with the reasonface-presentwhere its file is in a series marked present,face-verdict-on-other-pixel-datawhere its file is in a series marked absent but its pixel data are not those that the reviewed run wrote, such as a CT slice defaced since the reviewer saw it as received (D-050), or one whose written file the pack does not have, or of whose pixel data its previews do not show every frame, such as an instance listed as not previewed, one with more frames than its cine strip shows, outside a volume, or one whose native Pixel Data hold more than its frames, or whose pixel data have more frames than the pack showed, or that is an RT Dose with pixel data, by its SOP Class UID or a Modality that may be RTDOSE: unreadable, not text, of several values, with a character outside printable ASCII, or RTDOSE in any case, of more frames than its dose-levels previews showed, or of any where the review gives no dose levels’ counts, as only they show an RT Dose as it could show a face, or that is a Segmentation with pixel data, by its SOP Class UID, of Segmentation Storage or Label Map Segmentation Storage, or a Modality that may be SEG in the same ways, of more frames than its segments sheet showed, or of any where the review gives no segments sheets’ counts, as only a sheet shows a Segmentation as it could show a face, an instance that is both being held unless both showed every frame,face-verdict-on-other-contourswhere an RT Structure Set’s file is in a series marked absent but the contours it is written with are not those that the reviewed run wrote, such as one cut by a face block that the reviewed run did not find (D-052),face-verdict-on-other-gridswhere the file of an instance that holds a grid is in a series marked absent but the grids it is written with are not those that the reviewed run wrote, or cannot be read, andno-face-verdictwhere it is in none that the reviewer judged, such as a file changed since the review, or where it is an RT Structure Set whose contours, or an instance whose grids, the pack could not show, since the verdict on its series was given without them. A held instance is deleted with the staging area and never published. An instance that cannot show a face, such as an RT Plan, an MR Spectroscopy instance, or a spatial registration, satisfies the option. Where the run defaces a CT series (D-050), an instance that holds a grid, which the run does not cut, is held asundefaced-in-defaced-framewhatever its verdict where it names a defaced series’ Frame of Reference as its own Frame of Reference UID, the Registered Frame of Reference, in which its grids lie, or as the Source Frame of Reference UID (0064,0003) of an item of its Deformable Registration Sequence, since its displacements trace the face in either frame, where any of those is absent, empty, or cannot be read, or where it refers to a defaced slice, as the RT instances that the run does not clean are (D-052). Under Clean Pixel Data as well, an instance that the face review clears is still held for review while its pixel data await it (D-037), so a face verdict never releases an instance that another stage holds; such an instance is held for its pixel data alone, and one in a series marked present for both. A face verdict clears it only where the reviewed run blacked out the same regions, since other regions write other pixel data.An instance that satisfies the option gains its code, DCM 113102, and Recognizable Visual Features (0028,0302) set to NO, as E.3.2 requires, replacing any value already present (D-012). It gains the attribute whether or not its IOD defines it, so an RT Plan, RT Structure Set, MR Spectroscopy, spatial registration, Enhanced RT Image, or Enhanced Continuous RT Image instance that claims the option holds it as a standard attribute of a Standard Extended SOP Class (PS3.2 Section 7.3), as the maintainer chose on 13 October 2026 over releasing such instances without the option’s code or holding them. The conformance statement lists the code with those that an instance gains only after review, as it lists Clean Descriptors’ (D-009), and says when an instance gains it.
The verdicts are matched by digest, never by path or run position, so the second run may find the same files in another order, under other names, or among others. The release report’s
face_reviewsection gives the reviewed pack’s opaque reference; the method digest is unchanged, since the verdicts decide only which instances are released, never what a released instance holds (D-024).The option joins the options that the engine applies (D-011).
public-releaseselects it, as the maintainer decided on 25 October 2026 (Presets), and it is not enabled.
Rationale. E.3.2 requires that “sufficient removal or distortion of the Pixel Data” prevent recognition wherever there is “sufficient visual information” to allow it. Removing a face from pixel data, where the engine does (D-050), does not by itself show that recognition is prevented, so for an instance that can show a face the engine meets the option only where a reviewer judged that the condition does not hold. Holding the other instances keeps the claim true for every released instance, and releasing them without the code was rejected because the run would then drop a selected option for some instances silently. A second run was chosen over setting the attribute in the first run’s held output, because a held file is deleted and a published release is never added to (D-016). Matching source digests binds each verdict, through the attestation’s digest of the pack, to the exact bytes the reviewer saw previews of; a file changed since is not covered. Matching the digest of the pixel data written as well binds it to what the reviewer saw of them, and the pack records that digest only where its previews show every frame, a volume being shown by its projection and surface render, which draw each of its slices, pooling slices closer than their pixels by their maximum so that none is skipped, as a recognition system would reconstruct the face from them all, while only its dose-levels previews show an RT Dose as it could show a face (D-017), so a run under the option holds an RT Dose with pixel data, whatever its verdict, unless they showed every frame of it, and likewise a Segmentation unless its segments sheet did, since its cine strip and projection show a segment as windowed values rather than the surface that it traces; the run counts those frames itself from the pack’s previews, rather than taking the digest’s presence as enough, so that a verdict on either rests on the preview that could show its face, whatever wrote the digest; so under the option an Enhanced CT, MR, or PET instance of more frames than a cine strip shows is held, unless the Clean Pixel Data Option’s review showed each of its frames (D-037), a cost in what is released rather than a leak, since a verdict on a series releases only what the reviewer previewed, since a run can write other pixel data of the same file than the reviewed run did, by defacing it or by blacking out other regions, and a verdict on one is not a verdict on the other; the pair is matched, rather than the pixel data alone, so that the verdict stays one on a source file. An RT Structure Set has no pixel data, so the pack shows its contours as written on a contour sheet, drawn with the images they lie on, and the reviewer gives the verdict on its own series from that sheet (D-017); where the run defaces those images, its outline would still trace the face that they no longer show, so it is cut by the same block, or held whatever its verdict where it cannot be (D-052); its contours are digested apart from pixel data, so that the pack names what each digest covers. E.3.2 adds Recognizable Visual Features with no exception for an IOD that does not define it, and an instance that claims the option without it would not meet the option; adding it only where the IOD defines it was therefore rejected, and the validators’ findings of it in the other IODs are known differences that apply only to an output holding the option’s code, so the attribute added to any other output still fails the comparison. Defacing CT (D-050) does not let the option claim an instance by itself, since an instance whose face was removed still claims it only where a reviewer found no recognisable face. Its face block, the region to remove, is found from the image alone, in the patient’s coordinates: everything in front of a vertical plane 5 mm behind the centres of the two eye globes, perpendicular to the line between them so that it turns with the head, and superior to the lower globe’s inferior edge, lowered by a voxel or by the largest height along the patient’s superior axis of the region that a pixel stands for about the globes, whichever is larger, for the sampling, to the edges of the field of view: about the globes, the largest spacing between neighbouring slices times the z component of the slices’ unit normal, in magnitude, plus the heights of a step along a column and along a row, which, for a volume whose axes lie along the patient’s, is the largest spacing of its slices, rows, or columns along that axis across the globes’ height. The globes are found as the one pair of balls of soft tissue side by side, each with at least half of a sphere around it, and four fifths of one half of it, or seven tenths for a ball 9 mm deep or more, outside the soft tissue, as the orbital fat is behind a globe whatever touches its front, each with bone lateral and superior to it, and each just under the skin on the same side, with air within 20 mm in front of it, as only an eyelid and anything resting on it cover a globe (D-050); the head must lie behind them, and bone must enclose more above them, where the cranium is, than below. A volume without both eyes in view, with more than one such pair, with its face towards posterior, or upside down, as a patient position entered wrongly would give, or with no cranium in view above the eyes, is refused rather than guessed at, as is one whose row and column directions are not of unit length, or not perpendicular, within 10⁻⁴, or with two slices within 10⁻⁶ mm of each other along their normal. A volume whose slices do not lie along the patient’s axes, gantry-tilted, sheared within their plane, or oblique, is sampled to cubic voxels along the patient’s axes as any other is, by nearest neighbour, each voxel taking the slice nearest it along the slices’ normal and, within that slice, the pixel nearest it along the rows and the columns, so that its block is found as an untilted head’s is; a volume whose rows and columns each lie within 10⁻⁴ of a direction cosine of a patient axis, with its slices stacked along the third and offset within their plane by no more than 0.01 mm, is sampled by the functions that sampled it before, with the voxel side and the heights of its slices, rows, or columns taken from the same coordinates as before, so that its voxels, their values, and its block are those it had before, including at a voxel midway between two pixels or slices. The sampler’s checks are stricter than the finder’s were in two ways, both kept: it refuses row and column directions that are not perpendicular within 10⁻⁴, which the finder did not test, and two slices within 10⁻⁶ mm of each other along the normal, where the finder compared offsets rounded to 10⁻⁶ mm; so a volume that is not orthonormal, as PS3.3 C.7.6.2.1.1 requires, or that repeats a plane, which the finder once searched, is now refused as
not-along-patient-axes. A voxel beyond such a volume, in the corners of the voxels that a tilted stack leaves, takes the pixel at the volume’s edge nearest it, the nearest slice and, within it, the nearest pixel, as a point beyond the voxels takes the value at their edge. As the maintainer decided on 1 November 2026 (“Support now”), gantry-tilted and oblique head CT is supported under the option before the first release, without resampling what a run writes, so every pixel outside the block keeps its stored value. The region follows defaceRT’s (MIT licence), which removes everything in front of the centres of the eye contours from their lowest slice up, but lies 5 mm further back and needs no ROI names or image layout; defaceRT keeps the brain and the PTVs within its region by default, which D-050 weighs.Tests. A face review gives each verdict’s series’ source digests, and a pack that is not attested, whose attestation rejected it, or that was changed after it was attested, gives none; attesting refuses a face verdict with an outcome of rejected; a review is checked, and its repr shows only the reference and counts; an instance with any pixel data, an RT Structure Set, or a deformable registration with a grid, or whose Deformable Registration Sequence cannot be read, needs a verdict, and an RT Plan, an MR Spectroscopy instance, a spatial registration, or a deformable registration without a grid does not; a verdict covers only the grids that the pack showed, any other, unreadable, or unshown grids holding the instance as
face-verdict-on-other-grids, an instance without a grid needs no grid sheet, and a review’s grids are digests of files marked absent; a registration run alone is released given the verdict on its pack where its grid sheets showed its grids, held asno-face-verdictwhere its sheets were too tall, and held asface-verdict-on-other-gridswhere the run writes other grids; beside a defaced head CT, a registration marked absent whose own frame or Source Frame of Reference is the head’s, that refers to a slice of the head, or whose item names no Source Frame of Reference is held asundefaced-in-defaced-frame, one tied to the head in no way is released with its grid as written, and a later run without the CT still holds the others, as the reviewed run held them; a review is given to the transform exactly when the policy selects the option, and the option is applied but not enabled; the markers allow the option to go unsatisfied, set Recognizable Visual Features to NO with the option’s code, whether or not the data set’s IOD defines it, and otherwise leave it as received, and set it only to NO; the statement lists the code after Clean Descriptors’ as one gained only after review, and says when; the release report records the reference and counts the held instances by reason; a second run of the synthetic collection, its files renamed into the reverse order and given an attestation that marks the CT and RT Structure Set series absent and the RT Dose series present, releases the CT instances and the RT Structure Set with the code and NO, holds the RT Dose instances asface-presentand every other image asno-face-verdict, and releases the deformable registration, whose series is marked absent and whose grid the pack’s grid sheets showed, the RT Plan, the MR Spectroscopy instance, and the spatial registration with the code and NO; a review gives each file marked absent with the pixel data written of it, where the pack has them, and holds asface-verdict-on-other-pixel-dataa file marked absent whose pixel data are others, none, or unreadable; the pixel data’s digest takes each element’s tag, value, and pad byte; a pack lists the pixel data’s digest only for a released or held instance, as 64 lower-case hexadecimal digits, and a run lists that of each such file’s written pixel data, or none where reading it raises anything; each image of the compressed collection marked absent is held without its written pixel data and released with them, codestreams cut of their metadata included, its RT Dose images only where the review gives every frame as shown by their dose levels, and its label map Segmentation only where it gives every frame as shown by its segments sheet; and a corpus run given a face review that marks every file absent releases what the Basic Profile releases, the deformable registration included, its RT Dose images given every frame as shown by their dose levels and its Segmentations by their segments sheets, each instance with the code and NO, while every other run keeps Recognizable Visual Features as received, and the validators find nothing it introduces but Recognizable Visual Features in the IODs that do not define it, which the known differences explain only in an output that holds the option’s code; and the conformance statement names exactly the supported IODs that do not define the attribute; and the same second run under Clean Pixel Data as well holds the CT instances for their pixel data and asface-verdict-on-other-pixel-data, since their corners were not blacked out in the reviewed run, and the RT Dose instance for its pixel data andface-present, and releases the RT Structure Set, the deformable registration, the RT Plan, the MR Spectroscopy instance, and the spatial registration with the code and NO, and with Clean Pixel Data’s code and Burned In Annotation NO, since they hold no pixel data (D-048); and an analytic head’s region to remove is found from its eye globes, axial head first supine, feet first, prone, and prone feet first, and sagittal, through noise, a bolus over the eyes, thick slices, coarse pixels, and a long volume, holds the upper face and the air before it, where a mask would lie, keeps the back of each globe, the nose below the eyes, the mouth, and the back of the head, and turns with a head turned 20 or 25 degrees; it is the same for slices given out of order, and a wide gap between slices far from the eyes does not move it; and it is refused for a head without both eyes, a volume that cuts through them, spheres without a bony orbit, two heads in view, a head facing posterior, a head upside down, a volume that ends above the orbits, with or without bone below them, direction cosines that are not of unit length or not perpendicular, and two slices at one position; it is found, as the untilted head’s within a voxel, for a gantry tilt of 0.5, 15, and 30 degrees, a 15 degree tilt recorded as slices sheared within their plane, a 20 degree tilt feet first, a volume oblique by 10 degrees about the patient’s superior axis or by 12 and 8 degrees about two axes, and an oblique sagittal volume, the same for tilted slices given out of order, and refused for a tilted head without both eyes, facing posterior, or upside down; a voxel beyond a tilted, sheared, or oblique stack takes the pixel at its edge nearest it, as brute force finds it, and none lies beyond a stack along the patient’s axes; and the height that the block’s inferior limit is lowered by is the slices’ spacing for an axial volume, the rows’ for a sagittal one, nothing for one slice, the slices’ spacing for an axial volume whose rows rise 3 × 10⁻⁵ mm per millimetre, within the alignment tolerance, the spacing along the normal times its z component plus a row’s rise for a tilted or oblique one, and the widest gap between slices about the globes, not elsewhere; the voxel side of a stack along the patient’s axes, nearly axial, with a pixel spacing of 0.9999999 mm or 0.8 mm, or sagittal, is the one that its coordinates gave before; a stack that the old test of alignment takes, but whose directions are not perpendicular within 10⁻⁴ or whose slices lie within 10⁻⁶ mm, is refused; and the library refuses a run under the option without a face review, and a face review given without the option before reading it, refuses a pack that does not exist, holds no QC pack, has not been attested, or whose attestation rejected it, naming no path and creating nothing, gives the transform the pack’s verdicts, and, given the attested pack of its own run of the synthetic collection under the Basic Profile, releases the series marked absent and the RT Plan with the option’s code and NO, holds the series marked present asface-present, and names the pack in its release report; and the command gives the transform the verdicts of the pack given with--face-review, checks the policy before reading it, exits with status 3, naming no path and creating nothing, for a run under the option without one and for a pack that does not exist, holds no QC pack, has not been attested, or whose attestation rejected it, treats a face review without the option as an argument error, names the argument in its help, and, given the attested pack of its own run of the synthetic collection under the Basic Profile, releases the series marked absent and the RT Plan with the option’s code and NO, holds the series marked present asface-present, names the pack in its release report, and prints no path of it.
D-047: Clean Structured Content by the concept names of content items#
Decision.
The engine applies the Clean Structured Content Option (PS3.15 E.3.4) to the
tps-importandpublic-releasepresets, as the maintainer decided on 25 October 2026 (Presets), and to a custom option set. Table E.1-1 gives C under the option to the four sequences that hold content items, and the engine cleans three of them. All three are defined by the IODs of the first supported release: Acquisition Context Sequence (0040,0555), whose items are content items, in the Enhanced and Legacy Converted Enhanced images, the PET Image, and MR Spectroscopy; and Specimen Preparation Sequence (0040,0610), whose items each hold their content items in Specimen Preparation Step Content Item Sequence (0040,0612), in the Specimen Module, which every supported image IOD allows. The third, Content Sequence (0040,A730), whose items are content items that may each hold a Content Sequence of their own, to any depth (PS3.3 Table C.17-6), holds the content tree of Structured Reports, Key Object Selection documents, and encapsulated documents, of which the first supported release supports the X-Ray, Enhanced X-Ray, Radiopharmaceutical, and Patient Radiation Dose SRs, the Basic Text, Enhanced, Comprehensive, Comprehensive 3D, and Extensible SRs, and the Key Object Selection Document, Mammography CAD SR, Chest CAD SR, Colon CAD SR, Procedure Log, Spectacle Prescription Report, Macular Grid Thickness and Volume Report, and Waveform Annotation SR, and the Encapsulated PDF, which its document sequesters whatever its tree (Architecture item 7), and sequesters the others until their IODs are supported (D-010). It is cleaned wherever an IOD defines it, since the maintainer decided on 25 October 2026 that every option ships and that radiation dose reports, and then every other Structured Report IOD, join the scope. Waveform Annotation Sequence (0040,B020) is defined only by IODs outside that release, so it takes its Basic Profile action, as any sequence given C does (D-022). A Procedure Log’s entries, the items that are targets of CONTAINS from its root and that PS3.3 Section A.35.7.3.1.2 requires to be “strictly ordered by monotonically increasing Observation DateTime (0040,A032) Values”, keep that order where the options neither keep (Full Dates) nor modify (Modified Dates) their Observation DateTime: D gives each the dummy datetime of its rank, as the maintainer decided on 30 October 2026 (D-021). Where the source values are not in increasing order, are not DT values, or have different UTC offsets, the ranks cannot keep the order, so the log’s tree is not kept and the log is sequestered rather than written out of order.Under the option, each of the three sequences is kept where the IOD defines it at its place, and its items’ elements take their own rules, as in any kept sequence. So is each Content Sequence in a content item where the IOD defines it at its place, which is cleaned with the outermost one and never kept on its own; one that the IOD does not define there takes its own rule. The data set that holds the outermost Content Sequence is a content item too where it has a Value Type, as a Structured Report’s root is (PS3.3 Section C.17.3.1). Each content item, and each of its modifiers in Content Item Modifier Sequence (0040,0441), is looked up in Table E.3.4-1 (D-001) by the Coding Scheme Designator and Code Value of its Concept Name Code Sequence (0040,A043) and its Value Type (0040,A040), with NUMERIC, which the Content Item Macro (PS3.3 Table 10-2) uses, read as the table’s NUM. A concept name coded by a retired SNOMED designator, SRT, SNM3, or 99SDM, is looked up as the SNOMED CT code to which PS3.16 Table O-1 maps its SNOMED ID (D-001), as PS3.16 Section 8.1 has a receiving system map it.
An item whose concept name the table lists gives its value attribute, Text Value, Person Name, Date, Time, DateTime, or UID, the action that the selected options give the concept, or else its Basic Profile action. C under Clean Descriptors, which no cleaner of content items settles, falls back to the action without that option, as D-009 has an attribute’s C do where descriptor cleaning does not write it; where the remaining options give K and C, C applies, as
tps-importresolves Retain Device Identity’s K and Modified Dates’ C, though no concept has both in 2026d. C under Retain Longitudinal Temporal Information with Modified Dates is settled by its cleaner, by the temporal role of the value attribute (D-034). For a reference, a code, or a number, K and D need no change: the engine already replaces UIDs or keeps them under Retain UIDs, and keeps codes and numbers.X/D gives D wherever the concept appears, which the maintainer decided on 25 October 2026: at 20:13 UTC, that an X/D item a template requires takes a dummy value, as D-021 writes one, and at 21:02 UTC, that the engine reads every X/D item as required, the strictest reading, rather than matching each item to the template row it fills. D writes D-021’s constants,
DEIDENTIFIEDfor TEXT,19000101for DATE,000000for TIME, and19000101000000for DATETIME, or the second constant where the source value equals the first. D on the UID of a UIDREF item gives U’s replacement (D-003), which keeps a UID that the pinned tables register, such as a public frame of reference, and an item with no UID to replace cannot be kept, as D refuses one (D-021); this applies to the 11 UIDREF rows that the table gives D too. An IMAGE item needs nothing more, since its references’ UIDs take their own rules. Full Dates and Modified Dates still give their K and C, Retain UIDs and Retain Device Identity their K, and Clean Descriptors’ C falls back to D. Each of the 18 X/D concepts of 2026d is required (M or MC) by at least one template of PS3.16 2026d, of which one is cited here:Content Date (111018, DCM), DATE: TID 4020 row 9.
Content Time (111019, DCM), TIME: TID 4020 row 10.
DateTime Started (111526, DCM), DATETIME: TID 10003 row 6.
Device Observer UID (121012, DCM), UIDREF: TID 1004 row 1.
Device Serial Number (113880, DCM), TEXT: TID 1021 row 5.
Drug administered (122083, DCM), TEXT: TID 8131 row 7.
ECG Finding (271921002, SCT), TEXT: TID 3717 row 2.
Finding (121071, DCM), TEXT: TID 5226 row 3.
Frame of Reference UID (112227, DCM), UIDREF: TID 4122 row 2.
Procedure Action ID (121124, DCM), TEXT: TID 3100 row 2.
Procedure DateTime (122146, DCM), DATETIME: TID 3806 row 2.
Procedure Description (121065, DCM), TEXT: TID 2007 row 5.
Radiopharmaceutical Start DateTime (123003, DCM), DATETIME: TID 10022 row 9.
Recommended Follow-up Date (111054, DCM), DATE: TID 4002 row 9.
Referenced Segment (121191, DCM), IMAGE: TID 1411 row 7.
Study Date (111060, DCM), DATE: TID 2007 row 6.
Study Time (111061, DCM), TIME: TID 4122 row 5.
Subject ID (121030, DCM), TEXT: TID 1008 row 3.
Four rows that the table gives X take D too, as X/D rows do, which the maintainer decided on 25 October 2026 at 21:02 UTC, so that Enhanced X-Ray Radiation Dose reports (TID 10040) keep the rows that their templates require: DateTime Ended (111527, DCM), DATETIME, which TID 10042 row 4 and row 3 of each of TID 10043 to TID 10054 require; and the three rows of X-Ray Attenuator Model Data (128470, DCM), IMAGE, COMPOSITE, and UIDREF, of which TID 10051 rows 11 to 13 and TID 10052 rows 6 to 8 require exactly one (MC, “XOR”). Full Dates and Modified Dates still give DateTime Ended K and C, and Retain UIDs gives X-Ray Attenuator Model Data K. Every other X row still removes its item.
A reviewed list of supplementary rows, beside the generated table as D-022’s list is beside Table E.1-1, gives a row to concepts that the table omits, each by its Coding Scheme Designator, Code Value, and Value Type, with the actions of the attribute that holds the same information, as the maintainer decided on 25 October 2026 at 21:02 UTC. A row never covers a concept and Value Type that the table lists, and gives only X under the Basic Profile and K under Retain Patient Characteristics or Retain Device Identity. The rows cover, in PS3.16 2026d:
the patient characteristics that PS3.16’s templates code under concepts that the table omits, of which E.3.4 requires removing the information “corresponding to the Attribute information specified to be removed”: a coded Patient State (109054, DCM, CODE), in nine templates, among them TID 10024 row 2 of radiopharmaceutical dose reports; Subject Sex Parameters for Clinical Use Category (131233, DCM, CODE) and its Reference (131235, DCM, TEXT), TID 1007 rows 5a and 5c; Racial group (415229000, SCT, CODE), TID 1007 row 9 and TID 8300 row 2; Pregnancy observable (364320009, SCT, CODE), TID 2008 row 3 and TID 9001 row 21; and Tobacco Smoking Behavior (365981007, SCT, CODE), TID 3802 row 15 and TID 4301 row 8. Each is removed, and kept under Retain Patient Characteristics, as Table E.1-1 treats Patient State (0038,0500), the Sex Parameters for Clinical Use Category attributes, Ethnic Group and Ethnic Groups, Pregnancy Status, and Smoking Status. The comment on the sex parameters (131234, DCM, TEXT), TID 1007 row 5b, and Body Mass Index (60621009, SCT, NUM), TID 3602 row 9 and TID 10024 row 9, are removed under every option, Body Mass Index as the maintainer confirmed on 26 October 2026 at 06:46 UTC.
UDI (128739, DCM) as a CODE, TID 11004 row 26 and TID 11005 row 17 of imaging agent administration reports, whose code holds the entire Human Readable Form of the Unique Device Identifier (PS3.16 Annex D), removed, and kept under Retain Device Identity, as Table E.1-1 treats UDI Sequence (0018,100A) and Unique Device Identifier (0018,1009), as the maintainer decided on 29 October 2026 at 17:34 UTC. The table does not list the concept, so an unlisted item would keep the code, and with it the identifier.
Subject ID as a CODE (121030, DCM), TID 1007 row 3, which is required where the subject is not inherited, removed under every option. In 2026d’s templates, 23 pairs of a concept and a Value Type use a concept that the table lists only under other Value Types, and the maintainer decided that only this one is unkeepable, since it is the one whose value there holds what the listed row replaces with a dummy value: the identifier is the Code Value. The other 22 take the rule for unlisted items below, but for a coded Patient State, which the row above covers: X-Ray Radiation Dose Report (113701, DCM), listed as COMPOSITE, is the CONTAINER at the root of TID 10001, TID 10011, and TID 10040, which has no value of its own; Best illustration of finding (121080, DCM), listed as IMAGE and WAVEFORM, is SCOORD and TCOORD in TID 3909, and Source of Measurement (121112, DCM), listed likewise, is COMPOSITE in TID 2121 and TCOORD in TID 3530 and TID 3715, coordinates and references whose UIDs take their own rules; Identification of the X-Ray Source (113832, DCM), listed as TEXT, is a NUM in TID 10054 row 4, a source’s number rather than its identity; and 13 concepts listed as TEXT are CODEs in some templates, which hold codes from coding schemes: Patient State (109054, DCM), Stress Protocol (109056, DCM), Medication Type (111516, DCM), Processing step description (111703, DCM), Procedure Description (121065, DCM), Finding (121071, DCM), in 31 templates, Drug administered (122083, DCM), Procedure Result (122177, DCM), Acquisition Protocol (125203, DCM), Series Description (131563, DCM), Complication of Procedure (116224001, SCT), ECG Finding (271921002, SCT), and Finding Site (363698007, SCT), in 49 templates. Three are LOINC concepts listed as TEXT, which are containers without a value of their own or a coded indication: History (11329-0, LN), the CONTAINER of TID 2006 row 10 and the root of TID 3802, and Indications for Procedure (18785-6, LN), a CONTAINER in TID 1025, TID 3807, and TID 5320, and a CODE in TID 4201 row 4.
the patient’s height, weight, and body surface area, which PS3.16’s templates code in LOINC, as the maintainer decided on 26 October 2026 at 06:46 UTC, with the LOINC rows of Table E.3.4-1 (D-001): Patient Height (8302-2, LN, NUM), TID 3602 row 4 and TID 10024 row 5, and Patient Weight (29463-7, LN, NUM), TID 3602 row 5 and TID 10024 row 6, are removed, and kept under Retain Patient Characteristics, as Table E.1-1 treats Patient’s Size (0010,1020) and Patient’s Weight (0010,1030); Body Surface Area (8277-6, LN, NUM), TID 3602 row 7 and TID 10024 row 7, is removed under every option, as Body Mass Index is.
An item whose concept name neither the table nor a supplementary row lists keeps its codes and numbers, and its other values take their own rules: Table E.1-1 gives Person Name (0040,A123), Date (0040,A121), Time (0040,A122), and DateTime (0040,A120) D, and UID (0040,A124) U, and Text Value (0040,A160) has a supplementary rule, X/Z/D, which gives D where it is Type 1C (D-022).
A content item cannot be kept where the selected options give it X, which removes it; where its concept name is coded in NCDR, NCIt, or UMLS, whose rows the pin leaves out (D-001), or by a retired SNOMED designator with a code that Table O-1 does not map, or given by a retired SNOMED designator only by Long Code Value (0008,0119) or URN Code Value (0008,0120); where it is a UIDREF item with no UID to replace that its options give D; or where one of its modifiers cannot be kept. It cannot be read where its Value Type or concept name cannot be read as one Value Type and one code. Any other concept name given only by Long Code Value or URN Code Value is not listed. In Content Sequence, an item whose Value Type is CONTAINER, COMPOSITE, IMAGE, WAVEFORM, SCOORD, SCOORD3D, or TCOORD may have no concept name (PS3.3 Table C.17-5), and is then not listed, while the root and an item of any other Value Type must have one. An item of a by-reference relationship, which has a Referenced Content Item Identifier (0040,DB73) and neither a Value Type nor a concept name (PS3.3 Table C.17-6), gives no action, since its target is cleaned where it is in the tree.
Acquisition Context Sequence and Specimen Preparation Sequence take their Basic Profile action, which removes one where it is X and empties one where it is Type 2, in place of being kept, where any of their content items cannot be kept or cannot be read.
In Content Sequence, an item that cannot be kept is removed on its own, with everything in it, and the rest of the tree is kept, as the maintainer decided on 25 October 2026 at 20:13 UTC. Then, until nothing changes, an item whose Referenced Content Item Identifier (0040,DB73) names a removed item, or an item inside one, is removed too, whether it is a by-reference relationship or an item whose own elements hold the identifier, except that a TABLE whose cell, an item of Cell Values Sequence (0040,A808), holds the identifier loses only that cell, and is removed only where it loses every cell; an item other than a CONTAINER whose item of Relationship Type (0040,A010) HAS CONCEPT MOD is removed is removed too, while a CONTAINER, the root among them, is kept without that item; a CONTAINER whose items are all removed is removed; and any other item whose items are all removed keeps its own value and loses its Content Sequence, which is Type 1C, required only where the item has relationships (PS3.3 Table C.17-6). Each Referenced Content Item Identifier that is kept is renumbered, as a replaced value, to name the same item in the output (PS3.3 Section C.17.3.2.5). The plan still names every element by its path in the source, and lists the removed items; the writer leaves them out, and the preservation check and the check of the IOD’s requirements compare each element of the items after one where the output holds it, and allow an emptied Content Sequence to go.
The whole Content Sequence takes its Basic Profile action, D, which sequesters the instance, since a sequence has no dummy value (D-021), where an item at any depth cannot be read, where the root cannot be kept or is left with no items, or would be removed for its HAS CONCEPT MOD item, as a root that is not a CONTAINER would, or where an item is removed and a Referenced Content Item Identifier of the tree has no value or names no item of it.
The maintainer decided on 30 October 2026 at 12:52 UTC four rules that the defaults recorded with the decision of 25 October left open: an item one of whose modifiers in Content Item Modifier Sequence cannot be kept is removed whole, rather than kept without the modifier; a Referenced Content Item Identifier that names no item of the tree takes the tree out only where an item is removed, and is otherwise kept as the source has it; an item whose own elements hold an identifier that names a removed item, such as a TABLE in its Cell Values Sequence (0040,A808), is removed, as a by-reference relationship is; and an identifier with no value cannot be read, so it takes the tree out. On 31 October 2026 at 08:56 UTC the maintainer amended the last two:
A TABLE cell, an item of Cell Values Sequence, whose identifier names a removed item is removed on its own, rather than the whole TABLE, once PS3.3 Section C.18.10 was checked to allow it: Cell Values Sequence holds “each populated cell”, and “The table may be sparse (i.e., not every cell is required to be populated)”. The TABLE keeps its Number of Table Rows and Number of Table Columns, and its row and column definitions, and is removed, as a by-reference relationship is, only where it loses every cell, since Cell Values Sequence is Type 1 with one or more items. Any other item whose own elements hold such an identifier is still removed.
An identifier with no value is treated as one that names no item of the tree: it takes the tree out only where an item is removed, and is otherwise kept as the source has it.
The maintainer decided on 30 October 2026 at 23:36 UTC that an item of Content Sequence of Relationship Type HAS CONCEPT MOD that is removed, which modifies the concept name of the item that holds it (PS3.3 Section C.17.3.2.4), removes that item too, with everything in it and what goes with it, where that item is not a CONTAINER; a CONTAINER, the root among them, is kept without the modifier.
Every instance written under the option claims it, with DCM 113104. The conformance statement gives each of the three sequences C and describes the cleaning, and Waveform Annotation Sequence its Basic Profile action, and lists nothing as pending.
Rationale. E.3.4 removes the information in content items “corresponding to the Attribute information specified to be removed by the Profile and any other Options specified”, and Table E.3.4-1 names the concepts that carry it, so each listed item takes its row’s action, as an attribute takes its row’s. The supplementary rows follow D-022: where PS3.16’s templates code a patient characteristic under a concept that the table omits, an unlisted item would keep its code or number, and so release what E.3.4 removes and what only Retain Patient Characteristics may retain, so each row takes the actions of the attribute that holds the same information, and the option keeps it only where Table E.1-1 keeps that attribute. A coded Patient State takes K rather than the attribute’s C, because a code from a context group is already a value of similar meaning known not to contain identifying information, which C asks for. The comment on the sex parameters, free text that Table E.1-1 cleans, is removed under every option, because no cleaner of content items settles C, as Clean Descriptors’ C falls back for other text. Body Mass Index is removed under every option, as the reviewed rule for Patient’s Body Mass Index (0010,1022) removes it (D-022, D-038), so that a content item does not keep what its attribute loses, and so is Body Surface Area, which Table E.1-1 has no attribute for, as another measure of the patient’s body derived from height and weight. The rows for height, weight, and body surface area come with the LOINC rows of Table E.3.4-1, since generating those makes every other LOINC concept an unlisted item, which would keep these numbers. Making every one of the 23 Value Type mismatches unkeepable was rejected: X-Ray Radiation Dose Report is the root of every Projection X-Ray, CT, and Enhanced X-Ray Radiation Dose report, which would then be sequestered under every policy, and coded findings and finding sites would be removed from nearly every measurement report, while those items hold codes, coordinates, references, numbers, or no value, which the profile keeps in any kept sequence. An item that the table does not list is treated as the profile treats any kept sequence’s items, “recursively applying the Profile rules to each Data Set in each Item of the Sequence” (Table E.1-1a), so it keeps codes and numbers, as PS3.15 Notes 9 and 10 after Table E.1-1a say is usually safe, and its names, dates, free text, and UIDs are replaced as anywhere else. Removing every unlisted item was rejected because it keeps nothing that the Basic Profile’s emptying does not, while the profile rules leak nothing that they do not already accept for any kept sequence. An item of Content Sequence that cannot be kept is removed on its own, since removing the whole tree with it removes far more than the option requires and sequesters the report, as Content Sequence takes D, while most reports hold some optional item that the table removes, such as a Comment. The plan, the preservation check’s expectations, and every report still name each element by its path in the source, so that no path changes meaning; only the writer and the two checks of the written file map a path to the output’s numbering. A by-reference relationship to a removed item goes with it, since its identifier would otherwise name another item or none, and so does any other item that holds such an identifier, for the same reason, except a TABLE, which loses only the cell that holds it, since a cell that is not populated is allowed and the rest of the table still says what its source did. A CONTAINER left with no items goes, since it exists to hold them, while another item keeps its own value, which the option has already cleaned, and loses only the Content Sequence that PS3.3 requires only where it has relationships. Each identifier that is kept is renumbered, since it names its target by its position along the tree (PS3.3 Section C.17.3.2.5), which removing an earlier sibling changes. An item that cannot be read still sequesters the report, since the engine cannot vouch for what it read; so does a root that cannot be kept or is left with no items, which leaves no report; and so does an identifier that has no value or names no item of the tree where an item is removed, since it cannot be renumbered, while where none is removed it is kept as it is, as the source has it. An item with a modifier that cannot be kept is removed whole, since the modifier qualifies the item’s meaning, and the item without it would say what the source did not. The same holds for an item whose HAS CONCEPT MOD item is removed, except a CONTAINER: a modifier of a section’s heading, such as its language, qualifies only the heading, and removing the section would take every item in it, or the whole report where it is the root. Acquisition Context Sequence and Specimen Preparation Sequence keep the whole-sequence rule, since removing or emptying either never sequesters the instance, and their items have no identifiers to renumber. X/D gives D because the table’s D applies where a template requires the item, and removing such an item, under the whole-sequence rule that applied before single items were removed, took the tree with it: every radiation dose report that held its required rows, such as a device observer’s UID (TID 1004 row 1) or an irradiation event’s DateTime Started, was sequestered. Reading every X/D item as required follows D-020, which resolves a compound action from the strictest Type without evaluating a condition. Matching each item to the template row it fills was rejected as out of proportion to the gain: Content Template Sequence (0040,A504) names a template only on a CONTAINER that starts one, so templates that add items to their parent, such as TID 1004, are never named, and the match would need a matcher over all of PS3.16’s templates. A dummy value written where the item’s template allowed it to be absent reveals nothing (D-021). A UIDREF item takes U’s replacement rather than D-021’s, which replaces even a registered UID, because the item names a definition or an instance that the rest of the output names too: a Frame of Reference UID item of the registered Talairach frame (1.2.840.10008.1.4.1.1), which TID 1602 row 10 allows, would otherwise name a new
2.25UID while the image it describes keeps the registered one under U. The four X rows of DateTime Ended and X-Ray Attenuator Model Data depart from the table for those rows only: D is as safe there as removal, since a constant datetime and a replaced UID say nothing of the source, and it keeps the rows that the templates of Enhanced X-Ray Radiation Dose reports require. Other X rows that some template requires, such as Comment (121106, DCM) and Identifier (125010, DCM), still remove their items, as D-020’s plain X removes an attribute whatever its Type. The schemes whose rows the generated table cannot hold are treated the same way, so that an item that the full table might remove is never kept by a generic rule. LOINC’s rows are generated (D-001), so a LOINC concept that neither the table nor a supplementary row lists is unlisted, as a DICOM concept is, such as the LOINC titles and section headings of TID 2000 and the macular grid measurements of TID 2101. A code of a retired SNOMED designator names the same concept as the SNOMED CT code that Table O-1 maps it to, since PS3.16 Section 8.1 calls the coding scheme fully backward-compatible across SNOMED 3, SNOMED RT, and SNOMED CT, so it is looked up as that code; one that Table O-1 does not map, such as a provisional 99SDM code or a code that DICOM never used, might name a concept that the table removes, so it is treated as an unmatched scheme’s code is, and so is a long or URN code value, which no SNOMED ID is. Falling back from Clean Descriptors’ C follows D-009’s rule for a value that descriptor cleaning does not clean, so that a cleaner of content-item text can later settle it in its place. Cleaning Content Sequence before any supported IOD defines it changes no output, since a sequence is kept only where the IOD defines it, and lets Structured Reports join the scope without changing the cleaner. An item that PS3.3 lets go unnamed, such as an image reference or coordinates whose purpose is unstated, cannot be looked up, so it is treated as an unlisted item, whose references’ UIDs take their own rules, as an unlisted named reference’s do; refusing it would empty most reports that hold coordinates, whose IMAGE and SCOORD items are often unnamed. The root is looked up because it is a content item too, and a nested Content Sequence is never kept on its own because its items are cleaned with the tree that holds them.Tests. The engine applies the option, and Table E.1-1 gives C to the four sequences, three of which the engine cleans; each concept takes the action that its options give, X/D gives D, as do the X rows of DateTime Ended and X-Ray Attenuator Model Data and no other X row, Clean Descriptors’ C falls back to D for an X/D concept, and C applies over K; the schemes never matched are those the pin leaves out; a concept name coded by SRT, SNM3, or 99SDM is looked up as the SNOMED CT code that Table O-1 maps it to, so that a listed concept takes its row’s action, at any depth of a report and under each option that gives one, a concept the table does not list is not listed, and a concept to remove empties its sequence; without the option nothing changes; under it, an Enhanced CT Image keeps an Acquisition Context Sequence of unlisted coded, numeric, and text items, with the codes and numbers kept and the text replaced, and claims the option; a listed name is replaced; X/D TEXT, DATE, and UIDREF items and a DateTime Ended item are kept with D-021’s constants and U’s replacement of the UID, a Frame of Reference UID item names the same frame as the image, registered or not, and a UIDREF item with no UID is not kept, and an X/D image reference is kept with its UIDs replaced; the walker gives the content items’ actions with their own rule source; a listed item that the table removes, a concept coded by NCDR, NCIt, or UMLS, a retired SNOMED code that Table O-1 does not map or that is in another case, and an item that cannot be read each empty the sequence, while a LOINC concept that the table lists takes its row’s action and one that it does not list is unlisted; a long code value is not listed, unless its scheme is one the pin leaves out or a retired SNOMED designator, when it empties the sequence; modifiers are content items too; Retain Device Identity keeps a Device Serial Number, Full Dates keep an Acquisition Date and Modified Dates modify it, Retain UIDs keeps a Device Observer UID, which otherwise takes D, and Clean Descriptors falls back for listed text, and for unlisted text the reviewed descriptors list does not cover; Specimen Preparation Sequence’s content items are cleaned in a CT Image, and an item to remove empties it; a sequence that the IOD does not define at its place is not kept; in a Comprehensive SR, Content Sequence’s items are cleaned at any depth, with each nested sequence kept, and an item to remove, deep in a report or beside a section, is removed on its own, with the rest of the tree kept; the walker gives the tree’s actions and keeps a by-reference relationship’s identifier, and without the option sequesters the report; the root is looked up, so a root of Unique Device Identifiers empties the tree unless Retain Device Identity keeps it; a LOINC title and section heading of TID 2000, which the table does not list, are kept, and a report under them is written and released, while a LOINC Unique Device Identifier is kept only under Retain Device Identity; unnamed references and containers, and by-reference relationships, are kept, while an unnamed TEXT or PNAME item, an unnamed root, and a by-reference item with a concept name are not; a Content Sequence in an acquisition context item, where the IOD does not define it, takes its own rule; no supported IOD defines Content Sequence or Waveform Annotation Sequence; and the statement describes the cleaning. The synthetic corpus, with acquisition context items added to its Enhanced, Legacy Converted Enhanced, PET, and MR Spectroscopy instances, runs under the option alone, and under
tps-importandpublic-release, which keep and clean those items and release the corpus’s Structured Reports, with Retain Device Identity keeping a Device Observer UID undertps-import; of the two presets, onlytps-importwrites a UDI coded as a CODE. Under both, a report’s Study Time content item keeps its time of day, as Study Time (0008,0030) does, since Modified Dates moves a subject event by whole weeks (D-006), while its Study Date moves. Synthetic X-Ray and Radiopharmaceutical Radiation Dose SRs, built from their PS3.16 templates, check the action that each required and optional content item takes under each option set, including the dummy values for X/D concepts and the four reviewed X rows; which remaining X items are removed on their own; that a written report with every optional row holds the rest of its tree; and that a written report holds no source value its options do not retain. Synthetic Comprehensive SR, Comprehensive 3D SR, Key Object Selection Document, and Mammography CAD SR reports check the same tree and value rules, including that a finding site coded by its SNOMED IDs under SRT takes the same actions as one coded in SNOMED CT. Synthetic Chest CAD SR, Colon CAD SR, Procedure Log, Spectacle Prescription Report, Macular Grid Thickness and Volume Report, and Waveform Annotation SR reports check the same rules, that each optional row that the options remove is removed on its own, that a Macular Grid report keeps its findings, which TID 2101 codes in LOINC, and that each report with every optional row is written underpublic-releasewithout them and with no source value. The report tests check that a verified report keeps a dummy verifier under the reviewed rule (D-021). The corpus’s five dose reports, of TID 10001, of TID 10011 with TID 10015’s dose checks, and of TID 10040, TID 10021, and TID 10030, check each content-item marker, a TEXT item’s included, by its concept’s action, and a report made for a request has its required Requested Procedure ID emptied (D-020); the patient dose report’s estimate names the CT dose report, by the UID that the written CT dose report carries. The corpus’s Basic Text, Enhanced, Comprehensive, Comprehensive 3D, and Extensible SRs, each a TID 2000 or TID 1500 tree with a marker in the value of each PNAME and UIDREF item, are released by the run of Clean Structured Content alone, their Person Observer Names and source series replaced. The supplementary rows load, cover the concepts above and no row of the table, and a file with a malformed row, an action other than X or Retain Patient Characteristics’ or Retain Device Identity’s K, a row that the table lists, or a repeated row is refused; each row takes its attribute’s actions under every preset with the option added, the option alone, the option with Retain Patient Characteristics or Retain Device Identity, and every option, and a UDI coded as a CODE is removed on its own from a report unless Retain Device Identity keeps it; of the 23 Value Type mismatches, only Subject ID’s and Patient State’s CODEs have rows; in a radiopharmaceutical dose report, a coded Patient State, a Patient Height, and a Patient Weight in TID 10024 are kept only with Retain Patient Characteristics, andtps-importwith the option writes them, while a Body Mass Index and a Body Surface Area are each removed on their own under every option set; and in a Comprehensive SR, TID 1007’s sex parameters, their reference, and the racial group are kept only with Retain Patient Characteristics, while the comment on the sex parameters and a Subject ID coded as a CODE are removed on their own under every option set, so that such a Subject ID is never released, whether or not it is the Patient ID, and a report with every optional row of the general templates is written without the items its options remove. Synthetic CT (TID 10011, with TID 10015), Enhanced X-Ray (TID 10040), and Patient (TID 10030) Radiation Dose SRs, each observed by the device that recorded it, check that a report of required rows is kept under every option set, its required X/D rows and DateTime Ended taking D; which optional rows are removed on their own under each option set, among them TID 10015’s free-text Reason for Proceeding under every one; the action that each value of a kept tree takes; that unlisted free text takes Text Value’s own rule, so that a device’s Manufacturer and Model Name, which repeat the header’s, hold a kept report for review; and that a written report, verified or not, is otherwise released, and that one with every optional row is written without those removed. In a Comprehensive SR, a by-reference relationship to a removed item, or inside one, goes with it; a reference to an item after a removed one is renumbered at each level it passes, and one to an item before it is unchanged; a section whose items are all removed is removed up the tree, while one left with an item is kept; an item whose items are all removed loses its Content Sequence, which the walker removes without sequestering; a root left with no items takes the tree out, and so, where an item is removed, does an identifier that has no value or names no item of the tree, which is kept where none is; a TABLE cell that names a removed item is removed on its own, and is renumbered as a reference is, while a TABLE that loses every cell is removed, and a written TABLE keeps the cells that name kept items; an item with a modifier that cannot be kept is removed; a HAS CONCEPT MOD item that cannot be kept removes the item it modifies, with the reference to it and the section it leaves empty, while a section and the root are kept without it; and the walker removes each element of a removed item, keeps its siblings, and gives the renumbered identifier. A written X-Ray Radiation Dose SR’s renumbered identifier names the same item as its source’s, and an item whose items are all removed is written without its Content Sequence. The writer removes an item on its own, and refuses one that is not an item of a kept sequence, that is beyond its sequence’s items, or that holds a kept element; the preservation check refuses an output that keeps a removed item; and paths map between the source’s numbering and the output’s both ways. The corpus’s Key Object Selection Document, Mammography CAD SR, Chest CAD SR, Colon CAD SR, Procedure Log, Spectacle Prescription Report, Macular Grid Thickness and Volume Report, and Waveform Annotation SR, each built from its root template, are released by the same run, each content-item marker taking its concept’s action. Under the option alone, a Procedure Log’s entries take the dummy datetimes of their ranks, entries with equal times share one, an entry without a datetime takes none, and a series that would write a source value moves on; an observation context item’s Observation DateTime is not an entry’s, so a later one does not make the entries out of order; a log whose entries are out of order, not DT values, of different UTC offsets, or of a fraction without seconds is not kept, while one under Full Dates or Modified Dates, or another report, is kept whatever its order. Synthetic logs released underbasicandbasic-clean-descriptorswith the option added write four events one second apart from19000101000000, and one whose first two events are swapped is sequestered.
D-048: Reviewed redactions#
Decision.
A run under the Clean Pixel Data Option may be given the QC pack of an earlier run of the same files under the option, attested with redaction verdicts (D-016, D-037), as the maintainer chose on 12 October 2026, from the options of reviewing first and of a second run given the verdicts. As for face verdicts (D-046), the attestation must bind the pack, the pack every preview, and both must be of their formats. A pack that is not attested, or whose attestation’s outcome is rejected, a verdict on an instance that the pack does not list as cleaned and previewed, or lists without its source’s SHA-256, and verdicts that disagree on one source file, such as identical copies given different verdicts or recorded with different SHA-256s of their decoded frames, are refused when the verdicts are read, before the run starts. A cleaned instance that the pack lists as not previewed, such as one whose source could not be shown beside it, can have no verdict, and attesting refuses one, as it refuses any verdict given with an outcome of rejected (D-016).
A verdict names an instance by its run position, and the pack gives the SHA-256 of its source file, as the first run’s first pass read it. It is accepted, revised, or rejected. Accepted takes the regions that the pack lists for the instance, among them those that reviewed region rules gave (D-037), so the rules’ rectangles are blacked out again from the pack, without the rules. Revised changes those: the reviewer drops any of the finder’s regions that covers no text, and draws regions of their own, by frame index from 0, each region as
[top, left, bottom, right]as the pack gives its own, so that the regions kept and drawn cover every burned-in text that the reviewer saw; it drops or draws at least one region, never draws one that it drops in the same frame, and cannot drop a region that the pack does not list for its frame or that a reviewed region rule gave. As the maintainer asked on 1 November 2026, the reviewer drops and draws regions on the frames themselves, in the redaction review app, which saves them for the attestation command to read, rather than typing coordinates; an accepted or revised verdict also records the frames that the app showed the reviewer, and attesting refuses one that was not shown every frame that its review requires (D-059). Rejected releases nothing.An instance whose source file’s SHA-256 has an accepted or revised verdict has exactly those regions blacked out, without the finder, with the fill and the check of the written value that D-037 gives a finder’s regions. For compressed Pixel Data, the pack also records the SHA-256 of its frames as decoded, which the first run wrote and previewed, whether or not the finder found a region in them (D-037), and the regions are applied only to frames that decode to it again; frames that decode otherwise, or for which the pack records none, are cleaned by the finder and held for review, as a changed file is. Under Clean Recognizable Visual Features as well, a CT slice whose series the run defaces also has its face block written as air, and the face review decides on the pixel data so written (D-050). A reviewed region is never clipped: attesting refuses one that goes past the Rows or Columns that the pack records for its instance, or lies in a frame that the pack does not count, and a run given the verdicts checks again, so one that goes past its frame’s rows or columns, or lies in a frame that the Pixel Data do not hold, sequesters the instance as
redaction-mismatch. Otherwise the instance satisfies the option, and is released unless another stage holds it. An instance whose source file has a rejected verdict is sequestered asredaction-rejected. Any other instance with Pixel Data is cleaned by the finder and held for review, as in the first run, so a file changed since the review is held again.An instance without top-level pixel data satisfies the option in any run under it, since it holds no pixel data to clean, as an instance that cannot show a face satisfies Clean Recognizable Visual Features (D-046). The maintainer chose this on 18 October 2026.
An instance that satisfies the option gains its code, DCM 113101, and Burned In Annotation (0028,0301) set to NO, as E.3.1 requires, replacing any value already present (D-012). It gains the attribute whether or not its IOD defines it, so an RT Plan, RT Structure Set, MR Spectroscopy, registration, Enhanced RT Image, or Enhanced Continuous RT Image instance that claims the option holds it as a standard attribute of a Standard Extended SOP Class (PS3.2 Section 7.3), as D-046 has Recognizable Visual Features. The conformance statement lists the code with those that an instance gains only after review, and says when an instance gains it.
The release report’s
redaction_reviewsection gives the reviewed pack’s opaque reference, how many of the source files that it accepted or revised were reviewed in each mode, and how many of their frames the reviewer was not shown, which is 0 while every IOD’s review requires every frame (D-059); the method digest is unchanged (D-024). It describes the run’s own finder and region rules, which an instance with an accepted or revised verdict never meets, so D-024’s “the regions it finds are what the option writes” holds for every other instance; the finder that proposed the reviewed regions is described by the method digest of the first run, whose release report names the same pack by its reference.
Rationale. E.3.1 allows a process that “may require intervention of or approval by a human operator”, and its claim must hold for every released instance; the reviewer, who saw every frame of the instance as received and as written (D-037), gives that approval, so an instance whose frames the pack could not show can have none. A reviewer who rejected the pack has not approved what it holds, so its verdicts release nothing. Applying the reviewed regions without the finder releases exactly what the reviewer approved. Running the finder again and comparing its regions was rejected, since a finder whose output differs in another runtime would hold an instance that the reviewer approved, and added regions could never match it. Revised names the regions that it drops and draws rather than replacing the pack’s, as the plan of 12 October 2026 has it for added regions, so that leaving a region out of a verdict cannot release text that the finder found. Dropping a finder’s region that covers no text has been allowed since the maintainer asked on 1 November 2026 for the finder’s regions to be proposals that the reviewer keeps or drops, since blacking out anatomy removes image content that a recipient may need; a dropped region over text is the risk that it brings, and the app’s summary, which magnifies each dropped region in a window of its own, is there to catch it (D-059). A region that a reviewed region rule gave cannot be dropped, since the rule records text that a reviewer has already found at that place in every image of the kind (D-037); a reviewer who finds a rule wrong changes the rule. The drawn regions are applied without a further review, and the summary of the attestation lists each region dropped or drawn, beside the file in the pack that previews its frame, for the reviewer to check against that frame as they record it. A region inside its frame but misplaced, such as one whose coordinates are transposed or that is given for another frame, cannot be detected when it is attested, and would leave the text that it was meant to cover while the instance claims the option; drawing each region on its frame in the app, rather than typing it, removes those two errors, and a region drawn short of its text rests on the reviewer’s check of the app’s preview of the frame as it will be written and of the summary (D-059). A region past its frame is refused when it is attested, from the Rows and Columns that the pack records for the instance, rather than only when the second run applies it, since the pack is attested once, and a verdict found wrong only then could not be corrected. Attesting refuses a verdict given with an outcome of rejected, since the pack is attested once and the verdict could release nothing, so recording it would only mislead. Clipping a reviewed region, as a finder’s is clipped, was rejected because a transposed or mistyped region would then cover less than the reviewer meant, or nothing, while the instance claimed the option. Matching source digests binds each verdict, through the attestation’s digest of the pack, to the exact bytes whose previews the reviewer saw, as for face verdicts. For compressed Pixel Data, the source’s digest binds the codestream, not the pixels: the file written holds the decoder’s output, and another build or version of a decoder, or one that its codestream subverts, can decode the same codestream to other samples, most of all a lossy one, so the decoded frames’ digest binds the verdict to the samples that the reviewer saw written. The verdicts and their regions are decisions about particular files, bound to their digests and recorded by the reference of the pack that holds them, whereas the method digest identifies a method that applies to any file, as the reviewed-names list does by deciding values that recur across files (D-024); so they decide which instances are released and which regions are blacked out in them, but are not part of the method. Sequestering a rejected instance, rather than holding it, records in the release report that it will not be released, whereas a held instance awaits a review. An instance without top-level pixel data holds nothing that the option cleans, since the Basic Profile removes icons (D-037), and holding it or releasing it without the code would drop a selected option for it although it meets the option. E.3.1’s informative Note says that the option “is intended to apply to the Pixel Data (7FE0,0010) Attribute that occurs in the top level Data Set of an Image Storage SOP Instance”, as against the icon images that Table E.1-1 removes, and does not say whether an instance of another IOD may claim it; claiming it for an RT Plan, RT Structure Set, MR Spectroscopy, or registration instance is therefore the engine’s reading of E.3.1, met because such an instance holds nothing to clean. E.3.1’s normative text adds Burned In Annotation with no exception for an IOD that does not define it, and the validators’ findings of it in the other IODs are known differences that apply only to an output holding the option’s code, as for Recognizable Visual Features (D-046).
Tests. A redaction review gives each accepted instance’s pack regions, each revised instance’s pack regions with the reviewer’s added, and each rejected instance’s source digest; a pack that is not attested, or whose attestation rejected it, a verdict on an instance that is not cleaned or not previewed, and verdicts that disagree on a source file are refused; a review is checked, and its repr shows only the reference and counts; a verdict is checked, a revised one needs a region dropped or drawn, and none both drops and draws one region in a frame, an attestation with verdicts is read back as written, and one of an earlier format is refused; attesting refuses a verdict on an instance that is not cleaned, or is listed as not previewed, a region in a frame that it does not hold or past the Rows or Columns that the pack records for it, though not one that reaches its last row and column, a dropped region that the pack does not list for its frame or that a rule gave, an accepted or revised verdict that was not shown every frame that its review requires, and any verdict with an outcome of rejected; a review keeps a revised instance’s regions without those it drops, with those it draws; reviewed regions are blacked out alone, a frame without them is left as it is, and a region in a frame that the Pixel Data do not hold, or past the frame’s rows or columns, is refused; a review is given to the transform only under the option; the markers set Burned In Annotation to NO with the option’s code, whether or not the data set’s IOD defines it, and otherwise leave it as received; the supported IODs that do not define the attribute are those the statement names; the statement lists the code as one gained only after review, and says when; the release report records the reference and the count of frames not shown, and refuses a count without a reference; the attestation command reads the verdicts that the app saved for the pack, records each one, lists each region dropped or drawn with the preview of its frame, and refuses verdicts saved for another pack, or for this pack before it changed, and a verdict with an outcome of rejected; a second run of synthetic files, given the verdicts on its first run’s pack, releases an accepted and a revised image with their regions blacked out, the code, and NO, sequesters a rejected image as
redaction-rejectedand one whose added region goes past its frame, in a pack made to record more columns for it, asredaction-mismatch, holds every other image, and releases the RT Plan and the RT Structure Set with the code and NO; a second run with a finder of another method that finds nothing writes the reviewed regions all the same, never shows the finder an approved image, and releases no other image; a second run without region rules, given an accepted verdict on an image that a rule matched in the first, releases it with the rule’s rectangle and the finder’s region blacked out; under Clean Recognizable Visual Features as well, a revised region over more than air on a defaced CT slice holds the slice asface-verdict-on-other-pixel-data, and not for its pixel data; and a corpus run given a review that accepts a region in every frame releases what the Basic Profile releases, each instance with the code and NO, while the validators find nothing it introduces but Burned In Annotation in the IODs that do not define it; a pack’s SHA-256 of decoded frames read for each approved compressed instance, a malformed one refused, and copies of one source with different ones refused; and compressed Pixel Data whose frames decode to the reviewed SHA-256 released uncompressed with the reviewed regions, including a region that a reviewer added to an image in which the finder found none, whose child decode differs from the parent’s, and otherwise, or where the pack records none, cleaned by the finder and held again.
D-050: Defacing CT under Clean Recognizable Visual Features#
Decision.
Under the Clean Recognizable Visual Features Option, a run finds, after its first pass and before it writes any instance, the face block (D-046) of each series of CT Image, Enhanced CT Image, and Legacy Converted Enhanced CT Image instances, by Series Instance UID, and writes air, -1000 Hounsfield units, into the pixels of each slice of a defaced series whose centres lie in the block. A slice is a CT Image instance or a frame of an Enhanced CT Image or Legacy Converted Enhanced CT Image instance, and a series may hold either kind, or both. Every pixel outside the block keeps its stored value, so a slice wholly outside it is unchanged. Within the block, two kinds of pixel are kept: each of Pixel Padding Value or its range, and each of the brain in the cranial cavity, which bone at 300 Hounsfield units or more encloses within the slice, more than 30 mm above the higher globe’s centre, which keeps the brain above the orbits that lies in front of the block’s plane. The brain is the cavity’s pixels above -500 Hounsfield units that join, within the slice, such pixels behind the block’s plane, through pixels above -500 Hounsfield units that bone encloses at any height, and the cavity’s pixels that they enclose, such as air, but never bone, which is written as air, so that the brain is never more than the cavity. So the air of a frontal sinus, which bone walls in and so encloses too, is written as air, as is any tissue lining it, where the sinus lies ahead of the plane and bone parts it from the brain within the slice: kept, the sinus’s air would differ from the air written around it only by its noise, and its outline, which can identify a person, would remain. Where the sinus’s back wall reads below 300 Hounsfield units in a slice, as a thin wall can, its lining can join the brain, and the sinus is kept there, as is a sinus whose lining or fluid reaches behind the plane, since any of the cavity’s tissue behind the plane counts as brain. A slice with no brain behind the plane, such as a coronal slice ahead of it, keeps none. Where air’s stored value is itself in the padding range, the pixels written are padding, which a viewer shows as outside the image, as the air before the face is in most scans. Where no bone encloses the cavity within a slice, the slice’s part in the block is air, to the top of the slice. The maintainer chose keeping the cavity on 14 October 2026, over removing everything in front of the plane to the top of the volume, frontal brain included.
A slice need not lie along the patient’s axes: one turned by a gantry tilt, or oblique, spans heights, and each rule above applies pixel by pixel, by the pixel’s own centre, within the slice’s own plane. A pixel is in the block by its centre, and above the floor by its centre’s own height, so a tilted slice can keep the brain at its top and write air over the orbit at its front; enclosure by bone, and joining the brain behind the plane, are within the slice. Since the tissue that bone encloses joins at any height, a slice whose front a tilt raises, which reaches the brain ahead of the plane above the floor only through the brain below the floor, which it writes as air, keeps that brain, as an axial slice through each of its pixels would; for an axial slice, which lies at one height, this is the rule as before. Every pixel outside the block still keeps its stored value, so no slice is resampled. The face block’s finder takes such a stack by sampling it to voxels along the patient’s axes, and refuses as
not-along-patient-axesonly what it still cannot take (D-046).The block removes the skin, fat, muscle, and bone of the forehead, brows, eyelids, and upper nose, the lens and the front of each globe, and anything resting on them, such as an immobilisation mask. It keeps the back few millimetres of each globe, behind the plane 5 mm behind their centres, the nose below the eyes’ lower edge, the lips, the chin, the ears, which lie well behind the plane and which a block wide enough to take them would take the sides of the head with, and everything behind the plane. Planning loses the lenses and the front of each globe, and any dose-volume histogram of a structure in the block changes.
A series is defaced only where every instance can be read again from the file that the first pass read, with Pixel Data of one sample and whole bytes, native or compressed in a transfer syntax that a run decodes (D-037), of one frame for CT Image; where every slice has finite Image Position (Patient), Image Orientation (Patient), Pixel Spacing, Rescale Slope, and Rescale Intercept, a CT Image instance’s own, or, for each frame of a multi-frame instance, those of its Plane Position (Patient), Plane Orientation (Patient), Pixel Measures, and CT Pixel Value Transformation functional groups, each in either the frame’s item of the Per-frame Functional Groups Sequence or the Shared Functional Groups Sequence, never both, since PS3.3 C.7.6.16.1.1 lets a group be in only one and gives neither precedence; where every slice’s stored values are in Hounsfield units, a CT Image’s Rescale Type, which PS3.3 C.8.2.1 requires where they are not, being HU where present, and a frame’s, which its CT Pixel Value Transformation group requires (PS3.3 Table C.8-126), being HU; where the slices share their orientation, rows, columns, spacing, and Frame of Reference UID, and the stored values of each can hold air as one stored value without clipping, each slice by its own rescale; and where the face block is found from the slices that reach within 400 mm of the volume’s superior end, by their highest pixel centres, no two within 10⁻⁶ mm of each other along their normal, whose row and column directions are perpendicular within 10⁻⁴: each slice of an axial stack within 400 mm of the top one, every slice of a sagittal or coronal one, and each slice of a tilted or oblique one with any pixel within reach, whole. A gantry-tilted, sheared, or oblique series is defaced by the rules above for a slice that spans heights, its block found by sampling it to voxels along the patient’s axes (D-046), and the QC pack draws such a stack whole as a volume (D-017), so a face verdict on its previews can release every slice, as for an axial series. A series without a Frame of Reference UID is unreadable, and any failure to read a slice or find its block leaves the series undefaced with a reason, never stopping the run. Any other series, such as one without a head, one that the face block’s finder refuses, one with a CT Image instance of more than one frame, one with a frame whose functional groups cannot be read, one of other units than Hounsfield units, such as a multi-energy CT’s material map, one whose stored values cannot hold air, one whose slices share positions that nothing they name parts into phases, or whose phases disagree, or one with compressed Pixel Data that does not decode as D-037 decodes it, such as one in a transfer syntax that no plugin is pinned to, one whose decoder is not installed or whose decoding child cannot start, or one whose Basic Offset Table, frames, or codestream headers disagree with its attributes, is written as it would be without the option’s defacing, and the face review decides, as for every instance that can show a face (D-046): no series is held for review because it has no face block. As the maintainer chose on 31 October 2026, compressed slices are defaced as native ones are, from their stored values as decoded, by the plugin pinned to their transfer syntax and, where that plugin runs native code, in the decoding child (D-037), and an instance that defacing changes is written as Clean Pixel Data writes a cleaned compressed instance: its frames as decoded, with the air written, uncompressed in Explicit VR Little Endian, without the Extended Offset Table and its companions. An instance whose stored values defacing leaves unchanged, such as one wholly outside the block or one whose pixels in the block are air already, is written as received, its codestreams untouched, and one that the block does not reach is not decoded for writing. A lossy instance is defaced from its decoded samples, so the samples written outside the block are those that its decoder gives, which any reader of the instance as received would see. The plugin pinned to a transfer syntax decodes the same frames each time, so a second run writes the pixel data that a first run’s QC pack previewed and digested, and a face verdict binds to it as it binds to native pixel data. Each instance’s pixel data are decoded once for the finder and once more for the brain that defacing keeps, a frame at a time, so a multi-frame instance is never held decoded whole. The QC pack draws each frame of a defaced multi-frame instance in a volume of its own, or of its Concatenation, by the volume’s projection and skin-surface render, so a face verdict on those previews releases it however many frames it has, as it releases a defaced series of CT Image instances; an instance whose frames form no volume, such as one of frames at repeated positions in one stack and time point that nothing else parts, is drawn only by its cine strip, so one of more frames than that strip shows stays held as
face-verdict-on-other-pixel-data(D-017).The slices of a series that repeat a position along its slices’ normal, within a micrometre, as the time points of a respiratory-correlated CT or a perfusion scan, the phases of a contrast study, or two acquisitions that overlap do, are parted into phases by the time point or acquisition that each names, as the QC pack parts them (D-017), never by its order, and each phase’s block is found from its own slices alone, within 400 mm of its own superior end: such a series is defaced only where its slices part into phases, each at distinct positions, or else it is not defaced, as
repeated-positions; where all its slices lie on one grid within their planes, so that the slices of two phases at one position are of the same pixels, or else it isnot-one-stack; where each globe’s centre found from each phase lies within 8 mm, the radius of the smallest globe that the finder accepts, of the same globe’s centre found from every other phase, a placeholder to be set by validation, toward which, as the maintainer chose on 31 October 2026, the DICOM check (D-054) counts how far each series’ phases’ globes lie apart, or else it isphases-disagree, as a head that moved between phases, or globes found wrongly in one, would leave it; and where every phase gives a block, except that a phase from whose slices the finder finds no globes, as the second of two acquisitions that overlap below the eyes, is left to the block of the others where that block reaches none of its slices, since defacing would write nothing in them, or else the series isno-eyes. The series is then defaced by one block that holds every pixel of its slices that any phase’s block holds: its plane faces the mean of the phases’ anterior directions and lies 1 nm behind the point furthest back along it of each phase’s block within the rectangle of the slices’ pixels’ centres across the axial plane, its inferior limit is the lowest of theirs, and its globes are those of the phase whose higher globe is highest, so that the brain is kept only above the highest floor; a target is judged against this block and one slice at each position, as a series of one phase would place it, and an eye against the globes of each phase. Within the slices’ extent, so for every CT slice, it removes at least what each phase’s own block would; beyond it, as for an RT Dose grid or PET image wider than the CT’s field of view, its plane can lie in front of a phase’s by as much as their directions differ across that distance, where the CT shows no patient. Where the slices of two phases lie at one position, an RT Dose, RT Structure Set, PET image, or Segmentation in the series’ frame keeps only the pixels that every one of them keeps as brain (D-051, D-052). A series whose slices do not repeat a position is one phase, whatever its slices name, and is found as before. A series without a Frame of Reference UID is unreadable, and any failure to read a slice or find its block leaves the series undefaced with a reason, never stopping the run. Any other series, such as one without a head, one that the face block’s finder refuses, one with a CT Image instance of more than one frame, one with a frame whose functional groups cannot be read, one of other units than Hounsfield units, such as a multi-energy CT’s material map, one whose stored values cannot hold air, one of slices that share positions that nothing they name parts into phases, or whose phases disagree, or one with compressed Pixel Data, which would have to be encoded again, is written as it would be without the option’s defacing, and the face review decides, as for every instance that can show a face (D-046): no series is held for review because it has no face block. Each instance’s pixel data are decoded once for the finder and once more for the brain that defacing keeps, a frame at a time, so a multi-frame instance is never held decoded whole. The QC pack draws each frame of a defaced multi-frame instance in a volume of its own, or of its Concatenation, by the volume’s projection and skin-surface render, so a face verdict on those previews releases it however many frames it has, as it releases a defaced series of CT Image instances; an instance whose frames form no volume, such as one of frames at repeated positions in one stack and time point that nothing else parts, is drawn only by its cine strip, so one of more frames than that strip shows stays held asface-verdict-on-other-pixel-data(D-017).A PTV, CTV, or GTV, by RT ROI Interpreted Type, in an RT Structure Set of the run in the series’ Frame of Reference, or naming none, is kept with whatever lies between its contours, as the maintainer chose on 31 October 2026, in place of holding the series for it: each target, an item of ROI Contour Sequence, is judged by the convex hull of its own contours’ points, and a pixel in the block keeps its stored value where its square on its slice, given depth along the slices’ normal of half the smallest spacing between the slices that the block reaches (half the larger pixel spacing for a single slice), may meet that hull, so that the series is defaced around the target, and the reviewer’s verdict on the slices as written decides whether they still show a face. A series is not defaced, and each of its slices is held for review at the stage
visual-featureswith the reasontarget-in-face-block, where a target’s hull, within the block, reaches beyond the slices, where no image shows what would be kept: past the squares of the pixels, along their rows or columns, of every slice that may be nearest a point of that part, those from its least to its greatest extent along the slices’ normal and the nearest beyond each end, or more than that half spacing beyond the first or last slice along their normal, which linear programmes over the hull’s part in the block decide; where a target has a coordinate that is not finite or exceeds a kilometre in magnitude; or where a target has a contour with a Contour Slab Thickness or Contour Offset Vector, which PS3.3 C.8.8.6.2 retired, since its slab lies off the contour’s points, which alone place the hull. The hull holds whatever a planning system interpolates between contours, such as between contours drawn on PET slices that lie between the CT’s, or between sagittal ones, and each contour’s segments and interior, so that a sagittal or oblique contour crossing the block between its vertices is kept where it crosses; it errs towards keeping more of the face, such as the pixels between the arms of a target that wraps around the block’s lower rear edge, spanning the maxilla and the orbital apex, which the verdict then judges. A hull is the intersection of half-spaces, whose normals are those of Qhull’s facets and the target’s principal axes, each placed at the farthest of the target’s points along its normal, so that it holds every point; a flat or linear target, or a single point, has a hull of fewer dimensions. A pixel’s box is kept where its centre lies within each half-space widened by the box’s own extent along that half-space’s normal, and the hull’s extent along each of the box’s edges reaches the box, so that every box that meets the hull is kept, with at most a few beside it that do not. A series is also held where a target in another frame, whose contours cannot be placed without a registration, is in a structure set that ties that frame to the series’ slices, by a contour of an ROI in that frame drawn on one of them, or by the frame’s own list of contour images naming one, whatever other frames the set declares, or where a structure set searched for either cannot be read. Every structure set is searched that may be of the patient of a slice of the series, as it may be unless both give one Patient ID of printable ASCII characters alone, without its padding, and the two differ without case, whatever their Issuers of Patient ID, which planning systems write their own of or omit; a Patient ID that is absent, empty, not text, of several values, or holds any other character, such as a control character, a letter outside ASCII, or a fullwidth form, differs from none, since text that may be the same in another spelling, under Unicode normalisation or case mapping, cannot tell patients apart, and a rule of ASCII alone gives the same answer whatever Unicode version Python follows, and any other in the series’ frame, naming no valid frame, or drawn on its slices, since a target whose frame is unsure may be in the series’ frame whatever frames its set declares. Plain Patient IDs that differ only by a space or punctuation, such as12-345and12345, differ, so a structure set of the same patient whose Patient ID another system wrote so is passed over unless it is in the series’ frame, names no valid frame, or is drawn on its slices, and a target in it whose ROI names no frame is then neither kept nor holds the series. A target in another frame that the set does not tie to the series’ slices, such as one of another scan, is neither kept nor holds it. A contour’s frame is its ROI’s Referenced Frame of Reference UID; a target whose ROI gives none is taken to be in the series’ frame and in each frame that its structure set declares, so it is kept where its hull reaches the block, and holds the series where its hull reaches beyond the slices there or its set ties any of those frames to the series’ slices. Malformed input is taken the same way, so that it fails safe: an ROI’s or a declared frame of more than one value, or one that is not a UID, and an ROI’s frame that its set does not declare as one UID in one item, which PS3.3 C.8.8.5 requires it to, is taken as naming no frame and as each label it gives, so that a declaration of several values may name a frame but never makes an ROI’s frame certain, so that a label that its set ties to the series’ slices still holds the series, and an ROI Number repeated with different frames is taken to be in each of them as well.An eye of a structure set searched for targets, an ROI in the series’ Frame of Reference or naming none, a malformed frame counting as none as for a target, whose ROI Name names an eye, a globe, or an eyeball, by its words, alone or with its side, and not a lens, a cornea, a ring, or an avoidance region, has a contour point more than 25 mm from the nearer centre of the globes from which the block was found, or one that is not a number, or such a set that cannot be read again, means that the eyes disagree with the block. As the maintainer chose on 31 October 2026, in place of leaving such a series undefaced, the run defaces it with its block and holds each of its slices for review with the reason
eyes-disagree-with-rois, as it does each RT Dose, RT Structure Set, PET image, and Segmentation that it cleans by that block (D-051, D-052), until a reviewer confirms the block. The QC pack lists the series’ held slices among its eye checks, with the block’s SHA-256, of a label, the count and sorted SHA-256 of the series’ source files, and the block’s origin, anterior normal, inferior limit, and globe centres as big-endian 64-bit floating-point numbers, and draws aseries-eyessheet from the slices as received, before any is written: rows of an axial, a coronal, and a sagittal tile, 160 mm a side at 0.5 mm a pixel, through each globe found, then through the farthest point from both globes of each eye that disagrees, the farthest first, up to eight, an axial tile taken through the slice nearest its point, with the slices windowed from -160 to 240 HU, the block tinted, a cross at each globe’s centre and a circle where the tile cuts the sphere of 25 mm about it, and each eye’s contours where they cross the tile, within half a pixel or, along the slices, half their spacing, yellow within 25 mm of the nearer globe and red beyond. The sheet never counts as a preview that could show a face, since it shows the slices as received. A reviewer who sees that the globes found are the patient’s eyes confirms the block by the eye check’s first run position, which needs the sheet and an outcome of attested, and a later run of the same files, finding the block of that SHA-256, defaces the series without holding it for its eyes, and releases it, and the instances cleaned by its block, on their face verdicts as for any defaced series. A slice changed, added, or left out, or a block found otherwise, as by another version of the finder, gives another SHA-256, which no confirmation covers, so the series is held again with its sheet. A name’s words are those that an underscore, a space, other punctuation, a digit, or a change of case parts, such asEye,L, andPRVinEye_L_PRV05. A target that holds the series is the reason before the eyes, and a series defaced around a target has its eyes checked as any other. An eye in another frame, which cannot be placed without a registration, and an ROI that the set names otherwise, such as in another language, are not checked.Defacing never claims the option: a defaced slice claims it only where its source file is in a series that the face review marked absent and the pixel data written of it are those that the reviewed run wrote (D-046), so a verdict on a series seen as received does not release it defaced, and the slices that defacing changes are held as
face-verdict-on-other-pixel-data. A run under the option needs a face review, so the first run to deface a series is given a review with no verdict on it, which holds it, and its QC pack previews the slices defaced; the verdicts on that pack release the next run’s, which writes the same pixel data. Defacing CT thus costs one run more than a review of it as received. Under Clean Pixel Data as well, regions of text revised after the review change the pixel data written, so the slices are held until their faces are reviewed again.Beyond CT instances, the run cleans the same region, the face block of each defaced series of the frame in turn, of an RT Dose, set to zero there (D-051), and of an RT Structure Set’s contours and a Positron Emission Tomography, Enhanced PET, or Legacy Converted Enhanced PET image’s activity, cut or set to zero there (D-052). Any other RT Structure Set, RT Dose, or Positron Emission Tomography, Enhanced PET, or Legacy Converted Enhanced PET instance in a defaced series’ Frame of Reference keeps its contours and pixel data, so it is held for review at the stage
visual-featureswith the reasonundefaced-in-defaced-frame, whatever its own series’ verdict, unless a reviewer gave it a face verdict of its own, below, as is one of these that names no Frame of Reference in a run that defaces any series, or that refers to a defaced slice of a series in a frame that the run does not clean it in, as a structure set’s Contour Image Sequence can, whatever frame it declares, and one in a frame with a defaced series whose slices can no longer be read, whose kept brain cannot then be found. The hold goes by frame and slice references, not by what the instance shows, but an RT Dose without pixel data, holding only dose-volume histograms, shows no face and is not held (D-051). The QC pack lists each with that reason, and a verdict of absent on its series does not cover it in a later run, whatever that run defaces, since the reviewer judged it beside the defaced images. As the maintainer decided on 31 October 2026, the QC pack also lists each such instance, released or held, among its undefaced instances, by run position, with whether its previews show it, which they do only where those that could show a face draw every frame of the pixel data, every contour, and every deformation grid that the run wrote of it, as the pack’s digests of them record, and the attestation may give each that is shown a face verdict of its own, absent or present, from those previews of it alone, ininstance_faces, which a verdict on its series never replaces, a released one included, so that each later pack asks for it again. A later run holds such an instance by its own verdict in place of its frame, as it holds any instance by its series’ verdict: released with the option’s code on a verdict of absent where it writes the pixel data, contours, and grids that the pack showed,face-verdict-on-other-pixel-data,face-verdict-on-other-contours, orface-verdict-on-other-gridsotherwise, andface-presentwhere its own verdict, or its series’, is present, whether or not that run defaces its frame, and, where the run refused to clean it, whatever its frame’s series’ eyes, since no block cleans anything of it; an instance that a block of its own frame cleaned, held only because it refers to a defaced slice of a series in another frame, waits on its own verdict for that block’s confirmation, as any instance that the block cleans does. An instance that the pack does not show cannot be given one, and stays held asundefaced-in-defaced-frame; and the release report counts, in its face review, those held without a verdict of their own and those held with one, and names each released on one. A structure set’s outline can trace the face, and its contour sheet shows its contours as the run wrote them, uncut where the run holds it, drawn on the defaced images (D-017); RT Dose’s low-dose envelope and PET’s body outline can show the face too, and a reviewer may judge them beside the defaced CT. They are released only where the run cleans them (D-051, D-052), or on a verdict of their own, above. Any other instance in that frame, such as an MR series or a CT series that is not defaced, keeps its own verdict, which its own previews, of the pixel data it is written with, support. Each of them keeps whatever lies in a kept target’s hull, and what lies on the pixels that the CT keeps for it (D-051, D-052), so a target’s dose, activity, contours, and segments are never taken. Structure sets are searched for targets in the block of each series, and a target in another frame holds a series whose slices its structure set ties to that frame, as above. The QC pack renders each defaced series’ skin surface as the run wrote it (D-017).The release report’s
face_reviewsection counts, inct_series, the CT series that the run defaced, of them those in whose block it kept a target (defaced_around_targets), those whose eyes disagree with the block, held until a reviewer confirms it (defaced_eyes_unconfirmed), and those whose block a reviewer confirmed (defaced_eyes_confirmed), and those it did not deface, by reason: a face block finder’s refusal (not-along-patient-axes,no-eyes,ambiguous-eyes,head-not-behind-eyes,cranium-not-above-eyes, ortoo-large),unreadable,undecodable-pixel-data,not-one-stack,repeated-positions,phases-disagree,not-hounsfield-units,air-not-stored, ortarget-in-block, and names none of them.The finder samples to cubic voxels of 1.5 mm or more, or of the volume’s smallest spacing of rows, columns, or slices along their normal where that is larger, and at most 2^24 in all, refusing (
too-large) a volume that would need voxels larger than 2.5 mm, and takes the distance transform in slabs of 32 voxels along the slices, overlapped by the depth it needs, so that the memory a series needs is bounded whatever its length.As amended on 25 October 2026 from the counts of the HaN-Seg check (D-054), which refused 17 of its 42 CTs, the finder keeps a ball of soft tissue 9 mm deep or more, the depth at its centre, with 0.7 of the best half of its sphere outside the soft tissue, and a shallower one only with 0.8, as every ball before; a point of that sphere beyond the volume takes the value at the volume’s edge nearest it, as the finder’s averaging does, rather than refusing the ball. Each ball of a pair that passes the other tests of a pair must also lie just under the skin, on the same side for both, in front of the pair or behind it, the head’s test then telling the two apart: along the horizontal line from its centre perpendicular to the line between them, air, below -500 Hounsfield units, lies within 20 mm beyond the ball’s surface, the line taking the value at the volume’s edge beyond it, with no bone on the way and no more than 5 mm of values from -500 Hounsfield units up to the soft tissue before the two voxels of the skin’s edge. Exactly one such pair still gives the block, so more than one is still refused.
Rationale. Removing the face from CT is meant to let a reviewer find no recognisable face in head CT that would otherwise show one. Of the CT defacing methods tested against face recognition, defaceRT is the one built for radiotherapy data, and its code is permissively licensed: with one recogniser (FaceNet512 through DeepFace, at the cosine distance that maximised Youden’s index on the same pairs), frontal body-contour renders of 70 head-and-neck patients’ planning CTs matched their replanning CTs in 68 cases before defacing and 3 after, against 258 of 2,415 pairs of different patients (O’Sullivan-Steben and others, Med Phys 2025;52:e70160, preprint arXiv:2508.13914, sections II.C and III.B). For other defacing methods, built without radiotherapy data in mind, CT matches fell from 78% to 5% (Schwarz and others, NeuroImage 2022) and from 93% to 6% (Selfridge and others, J Nucl Med 2023, whose 7% is its PET figure, which defaceRT’s paper quotes for CT). defaceRT’s result is for its default, which keeps the brain and the PTVs within its block (section II.B), so keeping the brain and the PTVs follows the tested method. The brain is kept only above the orbits since an orbital roof can be thinner than a millimetre, so bone in a slice can enclose an orbit, or fail to seal it from the cavity, and an eye kept in front of the plane would undo the block; the 30 mm above the higher globe’s centre is the largest globe radius the finder accepts, 15 mm, and as much again, about 18 mm above an adult eye’s top, a placeholder, like the 5 mm margin, to be set by validation, and the reviewer’s previews remain the backstop. The brain carries no face, although brain anatomy can match scans of the same person, a risk under either choice since nearly all of the brain lies behind the plane. A target in the block is kept rather than removed, which would lose it for planning unseen; 4.9% (39 of 793) of defaceRT’s defaced CTs had a PTV overlapping its initial crop (section III.C.2), so holding each such series, as this decision first did, would leave a material share of head and neck CTs to manual review. Kept, a target’s region can leave part of the face, so the series’ release still rests on the reviewer’s verdict on the slices as written, which show it (D-046). Each target has its own hull, rather than one hull of them all, since one hull of two targets either side of the face would keep the face between them. A target whose part in the block reaches beyond the slices holds the series, since the dose, activity, and contours kept there lie where no slice shows the reviewer what they keep. A target is judged by the slices nearest it, not by every slice, since a gantry tilt that steps the slices along the table offsets each slice’s pixels within the plane from the last’s, by the step times the sine of the tilt, so that over a head the first and last slices can share little of the plane, and a target near the face would be held for lying beyond pixels that no slice near it lacks; along the patient’s axes every slice’s pixels lie alike, so the rule is as before. A tilted slice is defaced pixel by pixel rather than resampled to the patient’s axes, so that every pixel outside the block keeps its stored value, as the maintainer chose on 1 November 2026 in supporting gantry-tilted and oblique head CT; its brain joins at any height because a floor that also parted the tissue it joins would write as air the frontal brain just above the floor on each slice whose front a tilt raises, about a quarter of the brain kept in the block on the analytic head tilted by 30°, and a sixth at 15°, all of which axial slices keep. defaceRT places its block from the eye contours themselves; this block is found from the image alone, so a structure set’s eyes, where it has them, check it: an eye drawn away from the globes found means that the finder took something else for a globe, or that the set’s eyes are not where the image shows them, and either way the block cannot be trusted to hold the eyes until a reviewer has seen the globes it was found from beside the eyes drawn. Defacing the series while it is held, rather than leaving it undefaced, lets one review release it: the reviewer judges the face from previews of the slices as written, and confirms the block from the sheet of the slices as received, which shows the eyes that defacing removes, so a confirmed series needs no second run under review of slices seen as received. The confirmation is bound by its SHA-256 to the source files and the block, so a confirmation of one block never covers another, and the instances cleaned by the block wait for it too, since a wrong block would leave their face as it was. The sheet draws planes through the globes and the farthest point of each disagreeing eye since those are where a reviewer decides whether the finder took something else for a globe or the eyes were drawn elsewhere. The 25 mm is the largest globe radius that the finder accepts, 15 mm, and 10 mm more for an eye drawn with a margin, such as a planning organ-at-risk volume, or a globe found off its centre, a placeholder to be set by validation. Lenses, corneas, rings, and avoidance regions are left out since a name that holds an eye’s word can name them, and a ring or avoidance region need not lie near a globe. The check can find a block placed wrongly, never show one placed rightly, and the reviewer’s previews remain the backstop. Writing air in place keeps every byte outside the block. Compressed head CT, as archives and planning systems often send it, is defaced rather than left whole for the face review; it is written uncompressed rather than encoded again, as D-037 writes cleaned compressed Pixel Data, so the engine holds no encoder and a lossy codestream loses nothing more, and an instance that defacing leaves unchanged keeps its codestreams. A multi-frame CT is defaced by the same block, finder, and kept brain as the slices it holds, since its frames are the same images placed by functional groups, so that one acquisition is not defaced or left whole by how it was stored; its frames are read from their functional groups alone, as the Segmentation’s are (D-052), and a group in both sequences is refused rather than one chosen. A series whose Rescale Type is not HU is left undefaced, since its stored values do not map to the Hounsfield units in which the finder looks for the eyes and the brain, and air written in them would be another value. A series without a block is not held for that alone, as most series in a run show no head, and the review decides. Stored values that cannot hold air would need clipping, which writes another density, so such a series is not defaced. Searching only the 400 mm below the superior end bounds memory; a scan with the arms raised above the head may then show no eyes, which costs yield, never safety. In HaN-Seg’s CTs, the old finder refused 7 globes whose best half was 0.6 to under 0.8 outside the soft tissue, for soft tissue on every half that the counts cannot name, such as the extraocular muscles and the optic nerve may be, and 2 whose sphere reached beyond the volume; and in 12 CTs it found other pairs that passed every test of a pair, below and behind the eyes, or of a ball at an eye with one behind the eyes, so that 10 held more than one pair and 2 only such a pair, which the head’s test refused. A globe lies under its eyelid and anything resting on it, such as a bolus, while a ball deeper in the head has a globe, the orbital fat, or bone in front of it, so the test of air just in front of each ball refuses those pairs and keeps the rule that exactly one pair gives the block, rather than choosing the most anterior of several pairs, which would drop the refusal that stops a wrong pair from being used. The 20 mm is more than the analytic head’s eyelids under an 8 mm bolus, about 17 mm, and less than the tissue in front of a ball directly behind a globe, which has the globe’s diameter in front of it; the 5 mm of lower values allows for the averaging, and refuses a ball with the orbital fat in front of it. The lower share applies only to deep balls because 0.7 for every ball kept the layer of soft tissue over the analytic head’s cheekbones at 2.5 mm voxels, where a ball about 5.5 mm deep, as an infant’s globe may be, is still looked for, and three such pairs, beside and below the orbits, passed every test in a head without eyes; each of HaN-Seg’s 84 globes is 10 mm deep or more. The edge’s value is taken rather than air because air beyond the field of view would keep balls of soft tissue that the edge cuts, as where it cuts the face, and pass them through the test of air in front. The 9 mm depth and the 0.7 share were chosen with HaN-Seg’s counts in view, and its counts will check the 20 mm and the 5 mm, so HaN-Seg is tuning data for these settings, not an independent test of them: held-out evidence must come from the synthetic cases and the count-only check of DICOM exports, and the reviewer’s previews remain the backstop.
Tests. The face block is found from DICOM slices of an analytic head, per series; no head, a slice that cannot be read again, slices of another size, and unsigned stored values with no intercept leave a series undefaced with their reasons; a PTV, CTV, or GTV with a point in the block is kept, and the series defaced around it, as are a sagittal target triangle with no vertex in the block whose segment crosses it and two axial target contours, neither reaching the block, whose hull does, while two behind the plane, or two whose hull passes below the block’s corner, are not kept; a structure set that cannot be read, a point too far to place, or not finite, a target contour with a slab thickness or offset, though not one whose values are empty, and a target in the block reaching past the squares of the slices’ pixels at the patient’s right, or more than half their spacing above the top slice, hold the series, while one just within those bounds does not, while an organ, an outline, a target behind the plane, an ROI without a type, and a target in another Frame of Reference do not; slices beyond reach of the superior end are not searched; the outcomes are counted by reason; the air written lies within the block, covers the front of each globe, keeps the brain above the orbits and the padding, and is the stored value of -1000; bone enclosing an orbit within a slice keeps no part of the eye, which it would without the floor; a slice below the block has nothing written, and one whose air cannot be stored is refused; the pixel writer writes a mask’s value, sign included, after the text regions, frame by frame, refuses a mask of another frame or shape, of a value outside storage, or of colour data, and finds written pixel data that differs from the mask; the block found with the distance transform taken in slabs is the block found from the whole volume’s, its geometry must be finite, and a volume that would need voxels too large is refused; a slice without Image Position (Patient), with five direction cosines, non-finite spacing or position, a rescale too small to store air, a short Pixel Padding Value or limit, truncated pixel data, colour, or a series without a Frame of Reference UID leaves the series undefaced with its reason, never an error; a target whose ROI names no frame is kept; the brain is written as air 27 mm above the globes’ centres and kept 33 mm above, measured from the higher globe; a skull open within a slice keeps no brain, and padding that reads as bone closes no ring; a frontal sinus walled in by bone ahead of the brain, of air or lined with tissue, is written as air, which it was not before, in one slice and in every slice of a head with one, while the brain beside it is kept; a calcification within the kept brain is written as air, as bone always was; and the synthetic collection with its CT slices replaced by the analytic head’s, its CT series alone marked absent in the pack of a first run under the option, which previews them defaced, is released by a second run with each head slice carrying the option’s code and NO, defaced, with the eyes air, nothing outside the block changed, and the brain above the floor kept, while the Enhanced PET and Legacy Converted Enhanced PET instances in the same frame, also marked absent, are held as
undefaced-in-defaced-frame, and without a verdict, since the first run held them for the same reason, and one series is counted defaced; in a second run without the head’s slices, which defaces nothing, those instances are held without a verdict, since the pack held them for the defaced frame; RT and PET instances that name no frame, or refer to a defaced slice from another frame, are held, while one in another frame, and MR and CT instances, are not; a defaced series records its Frame of Reference UID and no other does; a structure set that names no frame is searched for targets, and a structure set in another frame drawn on the series’ slices holds the series if it has a target, in the block or behind the plane, and not for an organ alone; a target behind the plane in another frame, in a structure set with an organ in the series’ frame drawn on its slices, holds the series where its own contour, another ROI’s in its frame, or its frame’s list of contour images names one of the series’ slices, and not where none does, even with its contour in the block; a set naming only another frame and tied only by that frame’s list of contour images holds the series; a PTV whose ROI names no frame, by an empty or absent value, in a set naming only another frame and drawn on the series’ slices, or tied only by that frame’s list of contour images, holds the series though its hull misses the block, as does one in a set naming the series’ frame and another so tied; a PTV in the block is kept, the series defaced around it, where its ROI’s frame has two values, is not a UID, or is repeated under its ROI Number with another frame, and where its set names only frames that are not UIDs; a PTV in the block, in a set declaring only another frame and not tied to the series’ slices, is kept, the series defaced around it, where its frame is empty, absent, not a UID, of two values, repeated with another frame, or a valid UID that the set does not declare, or declares only among other values or twice in one value, while one declared alone as well leaves it defaced without it, and is not kept where the set gives another Patient ID, while a Patient ID absent, empty, of several values, holding a control character, inside it or after it, or spelt in other Unicode forms, such as composed and decomposed letters, fullwidth letters, or a dotless i, on the set or on one slice of the series, padding, case, or issuers, given on one side or differing, do not keep it from being searched, and a set of the Patient ID of either half of a series whose slices give two is searched; a PTV behind the plane whose ROI and set give the same label that is not a UID holds the series where that frame’s list of contour images names one of its slices, and not otherwise; a QC pack entry without its reasons gives no face review; marked absent in the pack of a run under the Basic Profile instead, each slice that defacing changes is held asface-verdict-on-other-pixel-data, and each it leaves unchanged released; a PTV in the block drawn past the front of the scan’s field of view holds every slice astarget-in-face-block, and with no series defaced the RT and PET instances marked absent are released, the structure set as received; an ROI is an eye by its name’s words in its usual forms, such asEye_L,LEye,Rt_Eye,Globe_R, andEye_L_PRV05, and not asLens_L,Eye_L_Lens,Cornea_R,Eye_L_ring,Eye-Avoid,Eyelid_L, orOrbit_L; an eye with a point beyond 25 mm of the nearer globe, above, beside, or ahead of it, or not a number, disagrees, while eyes at the globes, both in one ROI, and with a 5 mm margin agree, and an eye in another frame, or another ROI, is not checked, while one naming no frame is, as is one whose frame is not a UID, has two values, is given twice, has a component with a leading zero, or is not one that its set declares; on the analytic head, eyes at its globes leave it defaced, an eye 40 mm below its globe defaces it with the block that eyes at its globes give and holds it aseyes-disagree-with-rois, with a sheet of three rows, or two for a structure set that cannot be read again, while a confirmation of its block’s SHA-256 defaces it without holding it, another SHA-256 confirms nothing, a confirmation leaves eyes that agree as they are, a changed slice gives another SHA-256 for the same block, a run without sheets holds it with the SHA-256 alone, the counts give each defaced series by its eyes, and the frames of a series held for its eyes are unconfirmed; an outcome is consistent, and a block’s SHA-256 is of its sources in any order, but not fewer, more, or others, and of the block’s every value and its globes’ order; a target that cannot be placed is the reason before such an eye, and a kept target leaves such an eye to hold the series, an eye in another frame does not hold it, while one naming no frame in a set of another frame, searched as the same patient’s, does, and a structure set that cannot be read again for its eyes holds it; in the defacing runs, a structure set with the left eye drawn 40 mm below its globe has the first run’s pack list the head slices in one eye check, with its block’s SHA-256 and aseries-eyessheet of those slices that is not among the previews that could show a face; a second run given only the face verdicts holds every head slice, the structure set, both RT Doses, and the PET slices aseyes-disagree-with-roisalone, counted as defaced with its eyes unconfirmed, while one also given the confirmation releases each head slice with the pixel data that eyes drawn at the globes give, the option’s code, and NO, the structure set cut by the block, the RT Dose, and the PET slices, counted as defaced with its block confirmed and nothing held for the eyes; the sheet’s planes are each globe’s, then each disagreeing eye’s farthest point, the farthest first, up to eight, an eye within reach, with no finite point, or no contour adds none, and one with a point that is not a number adds one through its finite points; its tiles are oriented as the module describes and each pixel centre projects to its own row and column; an axial plane is taken through the nearest slice, only slices that a tile samples are wanted, slices in any order are sampled alike, a pixel beyond the slices is dark grey, padding black, the block tinted, the globes cyan, and an eye yellow within reach and red beyond, drawn only on planes within its slab; the QC pack refuses an eye check out of order, sharing an instance, naming one not held, or without a SHA-256 of its form, and a sheet of eyes across eye checks, of no eye check, or a second for one, and never counts its frames; an attestation records a confirmation and its face review gives the block’s SHA-256, and attesting refuses one of a position that begins no eye check, of an eye check without a sheet, given twice, not a run position, or with an outcome of rejected, as does reading a face review whose confirmation names an eye check without a sheet; the attestation command records a confirmation and refuses those; the release report counts the series by their eyes and refuses counts that are negative, not whole numbers, or more than the series defaced; and under Clean Pixel Data as well in both runs, each slice is held for its pixel data alone; on the analytic head, a ball is open to air only within the 20 mm, with no bone and no more than the 5 mm of lower values, and its eyelids, alone or under a bolus, are refused once the 20 mm is less than their depth; extraocular muscles that put less than 0.8 of a globe’s best half outside the soft tissue keep it, which 0.8 refused; at 2.5 mm voxels, balls of the soft tissue over the cheekbones with 0.7 to under 0.8 are not kept, with or without eyes, and keeping them gives more than one pair; a volume ending 15 mm above the globes keeps them, its top slice holding the orbits’ roofs, and is refused for its cranium, and one whose field of view cuts the eyelids keeps only the globes and refuses them, finding no air in front; and balls in bony cups below and behind the eyes, as temporal poles lie, and a ball at an orbit’s apex paired with the other globe pass the other tests of a pair but not the test of air in front, so the block is found from the globes, and a head without eyes is refused asno-eyes; and two balls one directly above the other, as balls on one column of voxels were in 15 of HaN-Seg’s CTs, are a pair given no test of air in front, no horizontal line lying perpendicular to the line between them, and are refused asno-eyes. The QC pack lists each undefaced instance, released or held, once, in order, with its source’s SHA-256, shown exactly where all its digests are given, and a run lists each released or held instance that its transform found undefaced, not a sequestered one or one without its source’s digest; an attestation gives an instance’s own verdict only on an undefaced instance that the pack shows, in order and each once, never with an outcome of rejected, and the command refuses an instance given both, and records each; a face review never takes an undefaced instance by its series’ verdict, held or released, takes it by its own, which binds it to the digests that the pack recorded, and holds it where its series is present, and a changed attestation that names another instance gives no review; the release report counts them, refusing a name not released, given twice, or not an output name, and a count that is not a whole number or is negative; and in the defacing runs, the Enhanced PET and Legacy Converted Enhanced PET instances and the deformable registrations tied to the head’s frame that the run does not clean are listed, shown, and each given a verdict of absent of its own is released as received with the option’s code, also in a run without the head’s slices and in a frame whose block is unconfirmed, one given a verdict of present of its own, or whose series is marked present, is held asface-present, and each released so is held again, asundefaced-in-defaced-frame, by a run given that run’s pack, whose series’ verdicts alone do not cover it; the grids that dose-levels previews cannot draw are listed as not shown and refused a verdict of their own, while one placed too far for its block to be found, which they draw in its own grid, is released on one as received; and an RT Dose set to zero in the block of the head’s slices, whose eyes disagree with the ROIs drawn, that refers to a slice of a second head series defaced in a frame of its own, is held on a verdict of absent of its own aseyes-disagree-with-roisuntil that block is confirmed, and then released set to zero, while the second series is released on its series’ verdict. An Enhanced CT Image or Legacy Converted Enhanced CT Image instance of the head’s slices gives the block that the slices give, whether its groups are shared or per frame, in any order of frames, and a series of several such instances and CT Image instances gives it too; each frame is written as air where its slice would be, by its own rescale, keeps the brain that its slice keeps, and gives its frame’s RT Dose, RT Structure Set, and PET the same block, released as beside the slices; a group in both sequences or neither, a group of two items, a Per-frame Functional Groups Sequence an item short, a frame without its position, spacing, slope, or Rescale Type, a frame or a CT Image of other units than HU, frames at one position, truncated pixel data, and a CT Image of two frames each leave the series undefaced with their reasons; and the whole run writes such an instance defaced frame by frame as the slices are written. With a second series of the head’s slices in the head’s frame, as a 4D CT’s average and phase series share one, both marked absent, each series is released written as the head’s series alone is, and two series are counted defaced. Slices in RLE Lossless, JPEG Lossless First-Order Prediction, and JPEG 2000 Lossless give the block that native slices give, alone or beside native slices in one series, and are written with exactly the stored values that native defacing writes, uncompressed in Explicit VR Little Endian, and a defacer reaches only a slice that its block holds; JPEG 2000 at a compression ratio is defaced from its decoded samples; native slices need no decoder, GDCM and pylibjpeg decode each slice once in the decoding child, and RLE Lossless decodes in process; only the frames that the block reaches are decoded for the kept brain, which is the native slices’ brain; an RLE Lossless frame whose header gives more segments than its samples fill, a Basic Offset Table that disagrees with the frames, a codestream whose header disagrees with Bits Stored, a transfer syntax that no run decodes, a decoder that is not installed, and a decoding child that cannot start each leave the seriesundecodable-pixel-data, and a compressed colour slice leaves itnot-one-stack; Enhanced CT and Legacy Converted Enhanced CT instances in each of those transfer syntaxes give the block that their native frames give; A target’s hull holds each of its points and agrees with a Delaunay triangulation’s inside and outside on random points, one of 20,000 points, whether a cloud or a circle whose every point is a vertex, is found and tested within 200 MB, as it is in blocks too small to hold its points or its facets, a flat, linear, or single-point target has a hull of fewer dimensions, and points that are not finite are refused; a pixel’s box that meets a tilted hull, found by sampling, is always kept across orientations, and an axis-aligned box exactly where it meets one; the reach along the normal is half the smallest step between slices, a repeated slice not counting, and the slices’ extent is that of every slice’s pixel squares; a hull beyond the slices along the normal, a row, or a column is found as such, and one within them is not; on the analytic head, a PTV before a globe keeps the nine pixels whose squares, with their reach, it meets on the slice 1 mm from it, and the rest of the block is written as air, while the slice 2 mm from it, beyond reach, is written as without it, only a target that may reach the block is kept, and a target’s pixels are kept for its frame even where they are padding; an Enhanced CT Image is written around a target frame by frame as its slices would be; a target’s contours are never cut, even between slices beyond their reach; and in the defacing runs, the analytic head’s CT slices in JPEG 2000 Lossless and RLE Lossless are released with the pixel data of the native run, those that defacing changes in Explicit VR Little Endian and the rest in their own transfer syntax, with the same series counted, and its PET and RT Dose so compressed are released as the native ones are; and the analytic head with a PTV before the right globe on three slices, marked absent as written, is released with the option’s code and NO, every pixel whose square meets the target unchanged, the rest of the block below the brain’s floor air, and counted as defaced around targets, while its structure set is released with the target as received and the outline and right eye on the target’s slices losing exactly what the CT writes as air, keeping their parts within the target, and its RT Dose and PET slice through the target keep their values within its hull while the rest of the block below the floor is set to zero. On the analytic head scanned with gantry tilts of 15° and 30° either way, a 15° tilt recorded as a shear, an oblique turn of 10° about the superior axis, and a compound oblique, plain, with a frontal sinus, with extraocular muscles, temporal poles, and an orbit’s apex, and under a bolus, each given the block found from its axial scan, every slice is written as air exactly at its pixels in the block other than the head’s brain above the floor, so the eyes, the forehead, the bolus, and the sinus are air and the brain is kept, including brain that a slice whose front is raised joins only through the brain below the floor; an axial slice is written as before; a tilted, sheared, or compound oblique series is defaced by the block that the finder finds from its own slices, within 2 mm of the axial scan’s globes, exactly so by that block; the finder is given each slice whose highest pixel lies within reach of the volume’s highest, and every slice of a sagittal stack; a PTV before a globe on a tilted or sheared CT keeps only pixels whose boxes may meet it and every pixel on which a point of it is placed, and holds the series where it lies beyond the pixels of its nearest tilted slices, and not where it lies within them though every slice’s pixels together would not reach it; a slice extent on a sheared stack is that of the slices nearest the span asked for, and a hull is beyond it exactly where it leaves those slices’ pixels; an axial RT Dose grid beside a tilted CT keeps exactly the voxels whose nearest tilted pixel the CT keeps in the block, none at the eyes or below the floor, an axial PET slice is set to zero activity in the block but there, and an outline on a tilted CT is cut by the whole block, written only behind its plane. Slices at distinct positions are one phase whatever they name; slices that repeat a position are parted by Temporal Position Identifier, or else Acquisition Number, and frames by Stack ID and Temporal Position Index, or else Frame Acquisition Number, never a single-frame instance with a frame, positions within a micrometre coinciding, values read as integers, and the phases ordered by their first slices, while slices that nothing parts, or a phase that still repeats a position, are not parted. The head’s slices as two time points or two acquisitions of one series, in any order of files, give the block of one, less a nanometre, each slice written as air as alone, and as two time points of one Enhanced CT Image instance, by Temporal Position Index, Stack ID, or Frame Acquisition Number, likewise; slices at one position that nothing parts arerepeated-positions, a second phase whose head lies 12 mm to the left isphases-disagree, and one moved 1 mm across its planenot-one-stack; a second phase whose head is shifted 3 mm and turned 2 degrees gives a block that holds every pixel that each phase’s own block holds, with the lower inferior limit and the higher globes; a second acquisition below the eyes is left to the first’s block, which reaches none of its slices, while a slab above the eyes, which it would reach, isno-eyes; an eye within reach of the second phase’s globes but not of the first’s holds the series, and eyes on both phases’ globes do not; a target in the enclosing block is kept, judged against one slice at each position, so that its reach along the normal is half the spacing between positions even where the second phase’s slices lie half a micrometre above the first’s, and a target in the block beyond the slices holds the series; the finder is inspected on the first phase; the brain kept beside the series, as an RT Dose’s block gives it, is kept only where each phase keeps it; and the outcomes are counted by reason. In the defacing runs, the head’s slices as two time points of one series are each released defaced, as one time point’s slices are, with the RT Structure Set, RT Dose, and PET beside them cleaned as beside one, and the series counted once as defaced.
D-051: Setting RT Dose to zero in a defaced CT series’ face block#
Decision.
Under the Clean Recognizable Visual Features Option, an RT Dose with pixel data whose only Frame of Reference UID is that of a defaced CT series (D-050) has, for each defaced series of that frame in turn, by Series Instance UID, the stored value 0 written into each voxel of its grid whose centre lies in that series’ face block, less the voxels that the series’ CT keeps: a voxel is kept where the nearest pixel of the nearest slice of the series that the block reaches, within half the slices’ smallest spacing (half the largest pixel spacing for a single slice), is one that defacing keeps, as cranial cavity or for a target (D-050). A voxel whose centre lies in the convex hull of a target that D-050 keeps is kept too, so a target’s own dose is never set to zero, and the 5% below applies to the dose around it. A voxel beyond the slices is otherwise not kept, so its dose is set to zero. Dose is never recalculated, and every stored value outside that region is written as received, as is each frame’s, and Dose Grid Scaling.
The grid is placed as PS3.3 C.8.8.3.2 defines: by Image Position (Patient), Image Orientation (Patient), and Pixel Spacing, and for each frame by Grid Frame Offset Vector, relative to the first frame where its first offset is 0, or, only where Image Orientation (Patient) is (1, 0, 0, 0, 1, 0) and the first offset is Image Position (Patient)’s z within 0.001 mm, as each frame’s z. A single frame without the vector lies at Image Position (Patient). A grid placed otherwise, whose Image Orientation (Patient) is not two orthogonal unit vectors, as PS3.3 C.7.6.2.1.1 requires, within 0.0001 in each vector’s length and in their dot product, with a spacing, or a coordinate of a corner of a frame, of magnitude above 1,000,000 mm, or with an attribute that cannot be read, of more than one sample, with compressed Pixel Data that does not decode (D-037), or with a negative stored value where its Dose Type is not ERROR, is not set to zero and stays held as
undefaced-in-defaced-frame(D-050).Where the greatest stored value that would be set to zero is more than 5% of the grid’s greatest stored value, nothing is set to zero, and the RT Dose is written as received and held for review at the stage
visual-featureswith the reasondose-in-face-block. The 5% is a placeholder, to be set by validation. For a grid of Dose Type ERROR, whose stored values are signed, since PS3.3 C.8.8.3.4.6 makes Pixel Representation 1 for it alone, magnitudes are compared, as the maintainer chose on 1 November 2026: the greatest magnitude that would be set to zero with the grid’s greatest magnitude. Such a grid, once set to zero, is still held, since no dose-levels preview shows a signed grid (D-017), so no verdict covers what it is written with, until the QC pack shows one. As forundefaced-in-defaced-frame, a verdict of absent on an RT Dose that the reviewed run held for this reason does not, by itself, cover it in a later run (D-046), since the reviewer may have judged it beside the defaced CT. The QC pack lists each such RT Dose among its dose checks, by run position, with the greatest stored value in the region as a fraction of the grid’s greatest and a SHA-256 that binds a reviewer’s choice for it to its source file and the face block (the block’s own SHA-256, of the series’ source files and the block, as D-050’s eye checks give it), and its attestation may give the reviewer’s choice for each, as the maintainer decided on 31 October 2026. Written as received, a later run writes it unchanged, without holding it asdose-in-face-blockor for a block that a reviewer has not confirmed, and a verdict of absent on its series, which binds the pixel data written of it to its own dose-levels previews, drawn from the grid as received, releases it with the option’s code. Set to zero, a later run sets to zero its region, as above, beyond the fraction, and holds it asdose-set-to-zero-on-reviewuntil the face review is of a run whose QC pack shows it set to zero, so that only a verdict of absent on its series from that run’s new previews of the grid as set to zero releases it, as for any RT Dose set to zero. A choice whose SHA-256 the later run does not give, for another source file or block, applies to nothing, and an RT Dose that the attestation gives no choice keeps the choice that the QC pack records its run applied. Each QC pack records the choice that its run applied for each dose check, and the release report counts, in its face review, the RT Doses held without a choice and, by choice, those held and the output name of each released.An RT Dose that names no Frame of Reference, or more than one, or is in a frame with a defaced series whose slices can no longer be read, is not set to zero, and is held as D-050 holds it. So is one that refers to a defaced slice of a series in another frame; one in the frame of a series set to zero is not held for referring to its slices. An RT Dose without pixel data, which holds only dose-volume histograms, shows no face, and is not held for its frame. An RT Dose set to zero by the block of a series whose eye ROIs disagree with its globes is also held, as
eyes-disagree-with-rois, until a reviewer confirms that block (D-050), since a wrong block would leave the dose at the face as it was.Dose-Volume Histograms, in this and any other RT Dose, are kept as received, so they describe the grid before any of it was set to zero, and no longer match a grid that was. A set-to-zero RT Dose claims the option, like a defaced slice, only where its source file is in a series that the face review marked absent and the pixel data written of it are those that the reviewed run wrote (D-046), which the QC pack records for an RT Dose only where its dose levels, drawn from the grid as written, set to zero, show every frame (D-016, D-017).
Rationale. An RT Dose’s low-dose envelope follows the skin wherever a beam enters or leaves, so a grid over the head can outline the face that defacing removed from the CT, and the defaced CT beside it would otherwise be held for nothing. Setting dose to zero in the CT’s region, on the grid’s own geometry, removes the same anatomy from both, and keeps every voxel outside it. The kept brain follows the CT’s own, looked up on its slices rather than recomputed, so that the dose follows what the CT keeps, and a voxel beyond the slices, which nothing kept, is set to zero. The tolerance on the direction cosines accepts cosines written to six decimal places; it bounds the vectors, not the voxels, whose error grows with their distance from the grid’s first voxel, to about 0.1 mm for one 500 mm along the normal, since the two vectors’ length errors compound in it. A grid with a spacing, or a coordinate of a frame’s corner, of magnitude above 1,000,000 mm is refused, since finite but huge geometry could put the block anywhere on the grid. Dose there matters for planning where it is a target’s, and RT ROI Interpreted Type is Type 2, so a target may be unmarked: a grid whose dose in the region is a material fraction of its maximum is held rather than cut. The fraction is of the grid’s maximum rather than of the prescription, since only an RT Plan, which may not be in the run, holds the prescription, and Dose Grid Scaling multiplies every stored value alike, so the stored values are compared. Where a frame has more than one defaced series, as a 4D CT’s average and phase series, or a planning CT and a repeat scan in its frame, do, their blocks and cavities can disagree, so a voxel is set to zero where any of them writes it as air, and kept only where none does, as the CT series beside it each lose their own; a frame whose series cannot all be read again is held, since a cavity cannot then be found. Placing a grid by anything but the offsets that PS3.3 defines would guess. A grid of Dose Type ERROR holds differences, which outline the skin as dose does, so it is set to zero as a grid of dose is, by magnitude, since a negative difference there shows the skin as much as a positive one, while a negative value in any other grid, which PS3.3 does not allow, still holds it. Dose-volume histograms are kept since they show no face, and recomputing them from a grid set to zero would describe no real plan. Holding every grid with dose in the region would hold the RT Dose beside nearly every head and neck series defaced around a target (D-050), whose dose around the target exceeds the fraction, so the reviewer chooses instead: a face verdict on the grid as received, from its own dose-levels previews, which can show the skin that its low-dose envelope follows, releases only those bytes, while a grid set to zero anyway is released only on a verdict on previews of the grid as set to zero, since a verdict may release only the bytes that the reviewer previewed. The choice is bound to the source file and the block, so it never carries to another grid or a block found otherwise.
Tests. A grid’s voxels in a fixed block are set to zero, less those whose nearest slice and pixel the block keeps, with relative offsets in each of four orientations, absolute offsets on an axial grid, and a single frame without offsets; voxels beyond the slices’ reach are not kept, a single slice reaches half its largest pixel spacing, and the nearest slice and pixel decide; a grid is held as
dose-in-face-blockonly where the dose set to zero exceeds the fraction of its greatest, dose in the kept brain not counting, and asundefaced-in-defaced-framefor a negative stored value, unless its Dose Type is ERROR, whose magnitudes are compared, and whose voxels of either sign in the block are set to zero; a grid with absolute offsets in another orientation or elsewhere than its position, without its spacing, position, orientation, or offsets for more than one frame, with too few offsets, zero or non-finite spacing, a short position, five direction cosines, zero, non-unit, or non-orthogonal direction cosines, cosines that are not numbers, huge spacing, offsets, or position, a frame placed beyond the bound, or colour, is refused, and oblique cosines rounded to six decimal places are accepted; a grid in RLE Lossless is set to zero as the native grid is; a defaced series gives its frame a block that keeps the brain above the floor and not the eyes, a frame with two defaced series is given both series’ blocks, in order of Series Instance UID, which together set to zero what either would; and no block is given without an RT Dose in the frame, for one naming none, for a series not defaced, or where a slice of either series in the frame can no longer be read; a grid set to zero is still held where it refers to a defaced slice of another series, and not where it refers to one of its own; the face review leaves out a verdict of absent on a file held asdose-in-face-block, unless the choice for it is to write it as received; a choice’s SHA-256 is of the source file and the block, each of 32 bytes, a dose check’s block SHA-256 is the series outcome’s or else that of its source files and the block, and a grid set to zero beyond the fraction is not held for it; the QC pack refuses a dose check out of order, given twice, naming an instance neither released nor held, without its source SHA-256, held with no choice, or with a fraction not in (0, 1], and lists each as the run found it; an attestation records the choices, in order, and refuses one for a position that begins no dose check or with an outcome of rejected, and its face review gives each by its SHA-256, or the pack’s applied choice where none is given, refuses a choice that names no dose check and two dose checks that share a digest, and records whether the pack showed the grid set to zero; the attestation command records both choices and refuses both for one position; the release report counts the RT Doses by choice, lists the output names of those released, and refuses counts that are negative or not whole numbers, names that repeat or are not released, and the section without a face review; and in the defacing runs, a grid with high dose in the block is listed for a choice, released as received with the option’s code on a choice of as written and a verdict of absent, without a confirmed block, held asdose-set-to-zero-on-reviewon a choice of set to zero, and released by a third run on a verdict on the second run’s previews, set to zero in the block below the floor and around the kept brain and unchanged outside it, while one set to zero by an unconfirmed block is held aseyes-disagree-with-roisas well; and in the defacing runs, the synthetic collection’s grids behind the block are released unchanged, a grid over the head with low dose in the block is released with the option’s code, set to zero in the block below the floor and around the kept brain and unchanged outside the block, a grid with high dose in the block is held asdose-in-face-blockand without a verdict, grids with zero, non-unit, or non-orthogonal direction cosines, or huge spacing, offsets, or position, are held asundefaced-in-defaced-frame, an RT Dose without pixel data or the Image Plane and Image Pixel modules is released with the option’s code, and in a run without the head’s slices, the grid set to zero in the reviewed run is held asface-verdict-on-other-pixel-data; with a second series of the head’s slices in its frame, the grid with low dose in the block is released as with one, and a grid of Dose Type ERROR over the head, its low differences of either sign, is set to zero rather than held asundefaced-in-defaced-frame, and held asface-verdict-on-other-pixel-data, since the pack shows no signed grid.
D-052: Cutting RT Structure Set contours, setting PET to zero activity, and clearing Segmentations in a defaced CT series’ face block#
Decision.
Under the Clean Recognizable Visual Features Option, an RT Structure Set is written with the contours of each ROI in a defaced CT series’ Frame of Reference (D-050) cut by the face block of each defaced series of that frame in turn, as D-051 places an RT Dose in it, and the contours of each ROI in a frame that the set declares and that holds no defaced series as received. A contour is written as received where none of its segments enters the block at a point whose nearest pixel, of the nearest slice of the series that the block reaches within half the slices’ smallest spacing, is one that defacing writes as air: a pixel in the block, other than one that defacing keeps, of the brain or for a target (D-050), at a point outside every kept target’s hull. Each segment is sampled within the block at half the smallest pixel spacing of those slices, and a point with no such slice counts where it lies in the block. So a contour behind the block, below it, or within the kept brain alone, as a brain contour above the orbits can be, is kept whole, as is a kept target’s own contour, which its hull holds. The closed contours of an ROI that lie in one plane, each contour’s plane being the one that fits its points best, so that it is found for either winding and for a contour that crosses itself, such as a bow tie whose lobes cancel in its signed area, and two contours lying in one plane where every point of one lies within 0.15 mm of the other’s plane, which allows for coordinates written to 0.1 mm and for a small hole whose own plane is uncertain, any two such contours joining their groups whatever their order, bound one region together, as a hole’s contour does within its outer one, whether by exclusive or, as PS3.3 C.8.8.6.3 defines it for
CLOSEDPLANAR_XOR, or as nestedCLOSED_PLANARcontours are commonly read, so where one of them reaches the face, each of them is cut by the same region, as below, and a hole is never left as a region that its outer contour no longer surrounds.Such closed contours lose only what defacing writes as air, as the CT does, as the maintainer chose on 19 October 2026, where they can: where each is simple, neither crossing nor touching itself once a point that repeats the one before it is dropped, as where a contour’s first point is written again at its end, all lie at one z above the block’s axial plane, and every point within them has one nearest slice of the series within half the slices’ spacing, whether or not it lies within the slice’s pixels, as their points nearest and farthest along the slices’ normal show, an axial one, whose unit normal lies within the alignment tolerance of the patient’s z axis, its z component within 10⁻⁴ of 1 in magnitude, or about 0.81°, the normal being scaled to unit length since direction cosines may differ from it by as much, with pixels that defacing keeps in the block. Face finding takes a gantry-tilted, sheared, or oblique series (D-046), whose slices D-050 defaces pixel by pixel, so the tilt check refuses those slices as well as those of a sagittal or coronal series, and their contours are cut by the whole block, as below, which removes more, while a target’s own contours, which its hull holds, are still written as received. Each is then written as its part behind the block’s vertical plane joined with its part ahead of that plane within the squares of that slice’s pixels that defacing does not write as air, those of the kept brain or kept for a target and those whose centres lie outside the block, each square being the points whose nearest pixel it is, so that its part beyond the slice’s pixels counts as in the block. The part within the squares is found exactly, by clipping to the bounds of each row’s runs of such pixels, and the pieces are joined along the edges that they share into rings, outer rings winding as the source contour does and holes the other way, so that a reader that fills by the nonzero rule still finds a hole where the source’s hole winds against its outer contour, each its own contour of the same type. A ring of no more than 10⁻⁹ mm², such as one of three points in a line that joining points within 10⁻⁹ mm of a pixel’s corner can leave, is dropped, and rings that meet only at points, around a gap, are written as they are, the gap lying outside each, so it is a hole of the region they bound for either type though no ring winds around it.
CLOSEDPLANAR_XORcontours combine by exclusive or (PS3.3 C.8.8.6.3), so a hole there is written as a contour of its own, but a reader may fill eachCLOSED_PLANARcontour alone, which would fill the hole again, and PS3.3 encodes such a hole only by a keyhole, which this step does not draw. So where aCLOSED_PLANARcontour’s rings would bound a hole, as a pixel written as air within the kept brain, such as bone that the brain encloses, makes one, its pieces are split along the edge between two columns of the slice’s pixels at the lowest column of the holes’ points, or the first such edge beyond it, and each side is joined again, until no ring bounds a hole. A hole that the edge crosses or runs along becomes a notch in the rings beside it, and none lies wholly on the edge’s lower side, so each split leaves at least one hole fewer, except where joining takes points within 10⁻⁹ mm of each other as one, which can leave as many holes or more; there the limit of 256 splits, below, still ends the splitting. The rings are then simple, wind as the source contour does, overlap nowhere, and together bound what the rings with holes would, so a reader that fills each alone, or that combines them by exclusive or or by union, finds the same region; an edge that two of them share lies between two columns of pixels, so it passes through no pixel’s centre. Where, for any of the plane’s contours, the rings’ signed areas do not sum to the pieces’ or a ring cannot be closed, or the edge beyond a hole’s lowest column misses it, as it can where the plane, not a pixel’s edge, bounds the hole there, or 256 splits do not free aCLOSED_PLANARcontour of holes, or one of its rings is not simple, as joining points within 10⁻⁹ mm of a pixel’s corner can leave one crossing itself, every closed contour of the plane is cut by the whole block instead, as below. A contour whose region loses no more than 10⁻⁹ mm² by this is written as received. A contour that is cut loses every square within it that defacing writes as air, such as one of bone that it encloses, while one that is not cut, since none of its segments reaches such a square, keeps the squares it encloses, as above. The squares of padding pixels in the block, which defacing leaves as they are, are not kept, so a contour that is cut loses them though the CT keeps them.Any other contour that reaches the face is cut by the whole block, the kept brain and the pixels kept for a target included, so that what is written of it lies outside the block or on its boundary. A closed contour, of Contour Geometric Type
CLOSED_PLANARorCLOSEDPLANAR_XOR, is written as each polygon of its part behind the block’s vertical plane and of its part ahead of that plane and not above the block’s axial plane, each its own contour of the same type; an open contour,OPEN_PLANARorOPEN_NONPLANAR, as each piece of it outside the block; and aPOINTcontour in the block not at all. A part is found by clipping the polygon against one plane at a time, and the pieces into which a plane cuts it are separated by pairing the points at which its edges cross the plane, in order along their line, as a simple polygon’s pair; where they cannot be paired, as for a polygon that crosses itself, the part is written as one polygon joined along the plane, which still lies outside the block. Each piece keeps its source contour’s other attributes, such as its Contour Image Sequence, with its Contour Data, written as decimal strings of up to 16 characters, and its Number of Contour Points; the first keeps its Contour Number, and the others have none, since a number names one contour of its ROI. An ROI left with no contour is written without its Contour Sequence, which is Type 3, and keeps its other attributes.A structure set is cut only where each of its ROIs names a defaced frame, or a frame that the set declares as one UID in one item and that holds no defaced series, under an ROI Number given once, each ROI Contour Sequence item refers to an ROI that it declares, each contour, in any of its frames, has a known Contour Geometric Type and Contour Data of finite coordinates, in threes, none above 1,000,000 mm in magnitude, and any Contour Slab Thickness or Contour Offset Vector that it carries can be placed, as below, and, in an ROI of which a contour is cut, each closed contour lies within 0.15 mm of one plane, so that it can be cut with those it bounds a region with. Any other, such as one that names no frame, one with an ROI in a frame that it does not declare so, or one in a frame with a defaced series whose slices can no longer be read, stays held as
undefaced-in-defaced-frame(D-050), as does one with a contour, or a frame’s list of contour images, that refers to a defaced slice of a series in another frame.A contour that carries Contour Slab Thickness (3006,0044) or Contour Offset Vector (3006,0045), which PS3.3 retired in 2021 and PS3.3-2020e C.8.8.6.2 defined as a slab of that thickness whose central plane is the contour moved by the offset, normal to its plane, the offset being zero without a thickness, is taken to cover every point that any reading of them gives: its Contour Data moved along its plane’s normal by every distance from the least to the greatest of its four readings: 0, as written; the offset’s component along the normal, the offset alone; less and plus half the thickness, the thickness alone; and that component less and plus half the thickness, both, or, for a contour without a plane, such as a
POINTor a line, along the offset itself, by up to its length. One whose thickness or offset is negative, not finite, above 1,000,000 mm in magnitude, of the wrong number of values, or unreadable, a thickness without a plane, and an offset that departs from its plane’s normal by more than 0.15 mm cannot be placed. A contour whose span reaches the block is cut so that no reading of what is written has a nearest pixel that defacing writes as air, keeping the brain kept, as the maintainer chose on 1 November 2026; closed contours of one plane are cut together, by the region that their common span gives, and only where they carry the same thickness and offset. Where they lie in one axial plane, their span runs along the patient’s z axis and the block’s vertical plane is upright, within 10⁻⁹, every height of the span is within reach of a slice, no two slices share a height, and the slices that the span reaches share one grid, their rows and columns along x and y within 10⁻⁹ and their pixels at the same x and y, so that a point’s pixel is the same on each, they are cut as a flat contour is, keeping their parts behind the vertical plane and, ahead of it, the squares of the pixels that every slice that the span reaches leaves unwritten, the kept brain on every one of them and those whose centres lie outside the block; a slice is reached where the heights nearer it than any other, within half the slices’ spacing, meet the span’s. Where no pixel whose centre lies in the block on any such slice is kept on all of them, and for any other such contour, or an open orPOINTone, the contour is cut by the region of every point whose span meets the block, found exactly as up to three half-spaces, the kept brain not spared, so that no reading of what is written enters the block. A reader places each contour’s slab by its own points, so the closed contours of a plane are cut by the span that holds each one’s own reading and the plane’s, along the plane’s normal, and the block grown, beyond each of its planes, by as far as any of their own readings can lie from that span, as their normals differ where their points are rounded; the kept brain is spared only where that is no more than 10⁻⁹ mm. Every contour with a slab that a cut writes, whether cut or left as it was, is then read again from its points as written, as a reader reads it, and must lie within 10⁻⁹ mm, beyond that growth, of each span that a cut judged it by, or the structure set is refused: so is one whose cut would leave a piece of an open contour straight, with a thickness that no reader can place, having no plane, or a sliver of a closed contour whose points no longer fix its plane. The current QC pack draws every reading of a slab contour (D-017), so the cut set may be released on its matching face verdict. A target or eye is searched for at every point of its span, and one whose span cannot be placed holds the series, as an unplaceable target or an eye that disagrees does (D-050): a target by the kept convex hull of its points moved to each end of their span, and an eye by the whole of each point’s span, every height of which must lie within the eye’s reach of one globe or the other, found exactly as the heights within reach of each, so that a span that leaves both globes’ reach between its ends, as between the two globes, holds the series.A PET image in such a frame, of one sample and native Pixel Data or compressed Pixel Data that a run decodes (D-037), has the stored value of zero activity written into each pixel whose centre lies in the block, other than one that defacing keeps, by the same nearest slice and pixel as D-051, or one whose centre lies in a kept target’s hull, and one of Pixel Padding Value or its range: a Positron Emission Tomography Image instance of one frame, placed by Image Position (Patient), Image Orientation (Patient), and Pixel Spacing and rescaled by Rescale Slope and Rescale Intercept, or each frame of an Enhanced PET Image or Legacy Converted Enhanced PET Image instance, placed by its Plane Position (Patient), Plane Orientation (Patient), and Pixel Measures functional groups and its activity given by its Real World Value Mapping functional group, each in either the frame’s item of the Per-frame Functional Groups Sequence or the Shared Functional Groups Sequence, never both. Each slice or frame needs an Image Orientation (Patient) of two orthogonal unit vectors, as D-051 checks them, a positive Pixel Spacing, its corners within 1,000,000 mm, and a zero activity that its stored values can hold. A Positron Emission Tomography Image’s zero activity is the stored value nearest -intercept / slope, by a Rescale Slope finite and positive and its Rescale Intercept, which give its values in its Units (0054,1001). A multi-frame PET frame’s Pixel Value Transformation is of unspecified units (Rescale Type
US, PS3.3 C.7.6.16.2.9), and its activity, in a unit of PS3.16 CID 84 (PS3.3 A.56.4), is given independently by Real World Value Mapping (C.7.6.16.2.11), whose items each map the stored values from their first to their last linearly or by a lookup table; its zero activity is the stored value nearest -intercept / slope of each linear item that maps it, which must be one stored value, mapped by one item at least, and the same for every item that maps it. A frame without that group, one with an item that maps by a lookup table, one with a slope of zero, or one whose items do not agree on one stored value of zero activity, is not cleaned. Each frame is set to its own zero activity. Any other PET image, such as one with a frame that cannot be placed or cleaned, compressed Pixel Data that does not decode, or a Positron Emission Tomography Image of more than one frame, stays held asundefaced-in-defaced-frame. A compressed PET image or Segmentation that this changes is written as a compressed CT slice that defacing changes is, uncompressed in Explicit VR Little Endian, and one that it leaves unchanged as received (D-050). Each defaced series’ block is applied in turn, with that series’ kept brain and targets.A Segmentation, of Segmentation Storage or Label Map Segmentation Storage, in such a frame, of native Pixel Data, or for
FRACTIONALandLABELMAPcompressed Pixel Data that a run decodes (D-037), one sample,MONOCHROME2, or forLABELMAPPALETTE COLORas well, which PS3.3 C.8.20.2 allows a label map, and unsigned pixels of the Bits Allocated that PS3.3 C.8.20.2 enumerates for its Segmentation Type, 1 forBINARY, packed eight to a byte with no padding between frames, so that a frame can start within a byte, 8 forFRACTIONAL, and 8 or 16 forLABELMAP, with Bits Stored the same, has each frame placed by its own Plane Position (Patient), Plane Orientation (Patient), and Pixel Measures functional groups, each from either the frame’s item of the Per-frame Functional Groups Sequence or the Shared Functional Groups Sequence, but not both, since PS3.3 C.7.6.16.1.1 allows a functional group in only one and gives neither precedence, or from the shared one alone where the Per-frame Functional Groups Sequence is absent, as PS3.3 A.51.5 permits where it would be empty, each a sequence of one item, with Image Orientation (Patient) of two orthogonal unit vectors and every corner of the frame within 1,000,000 mm, as D-051 checks them, and Pixel Spacing positive. Each pixel whose centre lies in the block, other than one that defacing keeps, by the same nearest slice and pixel as D-051, or one whose centre lies in a kept target’s hull, that lies in a segment, is written as the segmentation’s background, so that it lies in none: 0 forBINARY, whose 0 marks a segment’s absence, and forFRACTIONAL, whose 0 is a probability or occupancy of zero (PS3.3 C.8.20.2.3), and forLABELMAP, whose pixel values are Segment Numbers, its Pixel Padding Value, which alone marks a Segment Number as background (PS3.3 C.8.20.2.4), where it is one value that the pixels can hold, Pixel Padding Range Limit is absent, and an item of Segment Sequence describes it, since PS3.3 C.8.20.2.3.3 requires every value in a label map’s pixels to be described, so that writing it leaves none undescribed. Every other pixel is written as received. Any other Segmentation, such as one placed by a Derivation Image functional group alone, one with a placing functional group in both sequences, one with an empty Per-frame Functional Groups Sequence, one ofTILED_FULLframes, a label map without a Pixel Padding Value or with one that Segment Sequence does not describe, aBINARYorFRACTIONALone ofPALETTE COLOR, or one of compressedBINARYframes or of compressed Pixel Data that does not decode, stays held asundefaced-in-defaced-frame, as does one in a frame without a block, naming none, or referring to a defaced slice of a series in another frame. A cleared Segmentation, like a cut structure set, claims the option only where its source file is in a series that the face review marked absent and the pixel data written of it are those that the reviewed run wrote, which the pack records only where its segments sheet shows every frame of them, and only where that sheet, counted alone, showed every frame that it writes (D-017, D-046), so a verdict on one seen as received is held asface-verdict-on-other-pixel-data, as is one whose segments the pack cannot show; one with no pixel so written is written as received, and its verdict applies under the same condition.A cut structure set, or a PET image set to zero, claims the option, like a defaced slice, only where its source file is in a series that the face review marked absent and the contours or pixel data written of it are those that the reviewed run wrote (D-046), so a verdict on one seen as received is held as
face-verdict-on-other-contoursorface-verdict-on-other-pixel-data. A structure set, PET image, or Segmentation cleaned by the block of a series whose eye ROIs disagree with its globes is also held, aseyes-disagree-with-rois, until a reviewer confirms that block (D-050).The QC pack shows the reviewer each RT Structure Set’s contours as the run wrote them, drawn with the surface of a volume of its frame where the run wrote one (D-017), and records the SHA-256 of a structure set’s written contours only where it shows them, so a verdict on a structure set releases only the contours so shown, and one whose contours the pack cannot show is held as
no-face-verdict, since its series’ verdict was given without them. This meets the condition, set with this decision, that the Clean Recognizable Visual Features Option stay not enabled (D-033) until the pack did so; enabling the option is still a decision of its own.
Rationale. An outline of the skin traces the profile that defacing removed from the CT, and a PET image’s uptake at the skin outlines it too, so each would otherwise keep the defaced CT beside it held for nothing. Cutting the contours by the CT’s own block and pixels, rather than recalculating them from the defaced CT, keeps every point of them out of what the CT writes as air, and a contour that the block does not reach is written as received, so that the brain, the targets that D-050 keeps, and every structure behind the block keep their contours exactly. The plan for this step was to clip contours to the block less the kept cavity. Cutting every contour that reaches the face by the whole block was built first, since two planes cut exactly and remove more rather than less, but the outline then lost the front of the brain that the CT, RT Dose, and PET keep, leaving kept tissue and dose outside the body, and a brain contour drawn on the inner table, as segmentations commonly are, reached bone that defacing writes as air and lost its frontal lobe on those slices, for almost no gain in privacy, since the released CT shows the inside of the skull anyway. So a contour loses what the CT loses, as the maintainer chose. Its edge ahead of the plane follows the pixels’ squares, tracing the inside of the skull in steps, as the CT shows it. The squares are those of the nearest-pixel rule by which a contour is judged, so a contour keeps nothing that the CT writes as air, though it can keep up to half a pixel within the block beside a pixel whose centre lies outside it, which the CT keeps too. The cut is computed on the contours’ own polygons with NumPy alone, as the maintainer decided, rather than with a polygon library, and only where it is well defined, for simple contours in an axial slice’s plane; elsewhere the whole block, which removes more, cuts them. A contour is judged by the CT’s own pixels, as defacing writes them, so that a brain contour that crosses the plane within the kept brain is not taken to reach the face. Splitting a
CLOSED_PLANARcontour around a hole that the cut makes was chosen over cutting its plane by the whole block, as the maintainer chose on 20 October 2026, since bone within the kept brain, such as a crista galli or a calcification of the falx, would otherwise cost the outline and the brain all that the cut spares on those slices: in a model of the analytic head with both added, 5 of the 17 slices with pixels kept in the block, and about 46% of the area spared there. The split runs along an edge between pixels rather than through the hole’s centre, so that no pixel’s centre lies on an edge that two rings share. Cutting a plane’s closed contours together keeps the region that they bound exact, since cutting each by the same region cuts their exclusive or, or their union, by it, whereas a hole within the kept brain, kept whole inside an outer contour that was cut, would become a filled island. Pairing crossings along the plane separates a polygon’s pieces without the bridges that a single clipped ring would draw along the plane, which would put contours on the block’s boundary that the source never had. An eye’s contour keeps only the back of the globe, behind the plane, as the CT does, and a lens, wholly in the block, is removed, so planning loses them as it loses the front of each globe from the CT. A target is never cut, since defacing keeps its hull, which holds its contours (D-050). PET is set to the stored value of zero activity, the background of air, rather than to a background measured from the image, which would vary between slices and could itself outline the body. A PET image is placed by its own geometry, not by its series, so each slice is set to zero alone. Each frame of an Enhanced PET or Legacy Converted Enhanced PET image is placed by its own functional groups, as a Segmentation’s are, and set to its own zero activity, since its calibration is its own. That zero is taken from Real World Value Mapping rather than from Pixel Value Transformation, since PS3.3 gives a multi-frame PET frame’s rescale no units and lets it differ from the mapping that quantifies it, so zero after the rescale can be activity: with a rescale of slope 2 and intercept -100 and a mapping of slope 1 and intercept 0 Bq/ml, it is 50 Bq/ml. Every unit of CID 84 measures a quantity whose zero is the absence of what it measures, such as activity concentration, counts, or an SUV, so items of different units of the same stored values agree on zero; a mapping by lookup table is not read, and items that disagree, or a stored value mapped to activity by an item whose own zero lies outside what it maps, leave the frame uncleaned rather than choose between them. A Legacy Converted Enhanced PET frame without Real World Value Mapping, which its IOD makes optional, is held too, since its rescale, of unspecified units, does not say what its values measure. When this decision was made, a verdict of absent on a structure set released contours that the reviewer had not seen drawn, since the QC pack previewed pixel data, not contours, and an RT Structure Set’s verdict was given by its series without a view of its contours (D-046). The contour digest bound the verdict to the contours that the reviewed run wrote, so a set whose contours a later run writes otherwise, cut or not, was held rather than released on it, but it could not show the reviewer a face that a contour traces. So the option was not to be enabled until the pack rendered the written contours for the reviewer with the images they lie on, which its contour sheets now do, with every surface that an ROI hides behind its own and every mark that it would hide, to within two voxels, at most 4 mm, of its edge, and a set that a sheet cannot show records no contour digest, so that its verdict releases nothing. A Segmentation’s masks outline the skin as a structure set’s contours can, a mask of the body most of all, so the maintainer’s pick of 25 October 2026, to bring Segmentation into scope, needs them cleaned too. A segment is cleared where the CT is written as air, on the segmentation’s own frames, as PET is, rather than cut as a contour is, since its pixels, like the PET’s, are what it holds, and a mask that lies only in the kept brain, or behind or below the block, is written as received. A label map has no background unless Pixel Padding Value names one, since PS3.3 lets Segment Number 0 be a segment like any other, so writing 0 there could put the face into a segment, and a label map without one is held. Single-bit frames are unpacked and written one at a time, so that a long segmentation needs one frame unpacked at a time, a frame that starts within a byte keeping the bits of the frames beside it in the bytes that they share; the written file’s check reads each frame with pydicom, but every frame at once where one starts within a byte, since pydicom 3.0.2 reads such frames correctly together but not always one at a time. A segmentation that reaches the face is released only on a verdict on its segments as written, as a structure set is on its contours, since the reviewer of its series sees its segments only on its segments sheet, and so only that sheet’s frames count for it, as only dose levels’ count for an RT Dose; it was held without a verdict until the pack drew segments sheets and Segmentation came into scope. APALETTE COLORlabel map holds its labels as aMONOCHROME2one does, its palette only colouring them, so it is cleared alike, its palette unchanged, but only by a defacer alone, as single bits are, since a text finder would read its indices as intensities, while aBINARYorFRACTIONALsegmentation ofPALETTE COLOR, which PS3.3 does not allow, is held. A segmentation without the Per-frame Functional Groups Sequence is placed by its shared groups, since every frame then shares them, while an empty sequence, which PS3.3 does not allow, is held. A structure set naming several frames, such as one with ROIs on a planning CT and on a registered MR, is cut frame by frame, since each ROI’s frame places it, and an ROI in a frame that holds no defaced series keeps its contours, as any instance of that frame keeps its own, while an ROI whose frame the set does not declare, and a contour referring to a defaced slice of another frame, are held, since placing them against the block would need a registration. A contour with a slab is cut by every reading of its retired attributes, since a reader written before their retirement may draw it moved or thickened and one written since may ignore both; it keeps only the brain that every slice its span reaches keeps, since the span crosses those slices and a reading may lie on any of them, and where the slices cannot be judged together, as where they do not share a grid, it is cut by the whole block moved back along the span, which removes more.Tests. A contour that reaches no pixel written as air, behind the block, below it, or within the kept brain, is kept whole, and one wholly in the face is removed, as is a
POINTin it; a closed contour that reaches the face keeps its part in the squares of the pixels that defacing does not write as air, kept pixels that a mirror image of them would not match, forCLOSED_PLANARandCLOSEDPLANAR_XOR, as 200 random star-shaped polygons on such a slice do exactly, by an independent polygon library, or are kept whole only where they reach no pixel written as air but at a graze, and as a rectangle does with its first point written again at its end or a point repeated within it, and on slices whose direction cosines fall 6 × 10⁻⁵ short of unit length, while a triangle near the midpoint between two slices tilted within face finding’s tolerance, its one corner within their pixels nearest one and points within it nearest the other, is cut by the whole block, so that it keeps no pixel that the other writes as air, and around a pixel written as air within the kept brain, as a hole of its own forCLOSEDPLANAR_XOR, and forCLOSED_PLANARas rings split along the edge before the pixel’s column, as it does around holes in one column and in another, and as 150 random star-shaped polygons of each winding do around random pixels written as air, each ring simple, winding as the source does, overlapping no other, and meeting another along a line only at an edge between columns of pixels, their union exactly the contour’s part in those squares, by an independent polygon library, while aCLOSED_PLANARcontour that the limit on splits leaves with a hole is cut by the whole block, as is an L-shaped one whose inner corner lies 10⁻⁹ mm from a corner of a pixel written as air on a grid turned 133.1° where its split rings would cross themselves, and where joining would leave a ring of no area, none is written, and two rings that meet at points around gaps are written as they are for either type, while contours of a plane at more than one z, a sagittal contour, a polygon that crosses itself, open types, and every closed contour of a plane where the pieces of one cannot be joined into rings are cut by the whole block; a cut contour keeps its winding, so that a clockwise or anticlockwise outer contour and a hole within the kept brain that winds against it bound the same region by the nonzero rule as by exclusive or; the pieces of a polygon within chosen pixels, and the rings they join into, are exactly its part in the pixels’ squares, by sampled points, for 200 random star-shaped polygons on grids turned, flipped, or along the axes; pieces that tile an L, meet at a corner, surround a gap, or share an edge split unevenly join into the region’s rings; a contour below the cavity’s floor, or beyond the slices, is cut where it enters the block; an edge that crosses the block between its vertices is cut; a hole within the kept brain, or crossing the plane, inside aCLOSEDPLANAR_XORor nestedCLOSED_PLANARcontour that reaches the face is cut with it, so that the region they bound is its part outside the block, as it is for 200 random holes and for either winding of each contour, either order, and the same contours and block translated below the origin, while a contour and its hole in another plane, within the kept brain alone, are kept whole, and contours in parallel planes either side of the origin are not taken for one plane, while 300 oblique contours and holes of 0.3 to 2.5 mm, far from the origin and written to 0.1 mm, are, and a contour 0.5 mm beside them is not; a small contour half a millimetre below a contour and its hole, turned so that its plane passes through the outer contour’s centre, leaves the hole grouped and cut with the outer contour in every order; a hole within the kept brain in a bow tie’s lobe, for either winding of each and either order, stays excluded, nothing in the block is included, and the rest is as it was, by counting crossings; a closed contour with a point 1 mm from its plane refuses an ROI that is cut, and is kept in one that is not; a U-shaped contour cut in two is written as two, numbered once, and a polygon that crosses itself is written outside the block; 200 random star-shaped polygons near the plane are each cut to exactly their part outside the block, by an independent polygon library, or kept whole only where they enter the block no deeper than its nearest pixels; a sagittal contour is cut by both planes; open contours are written as their pieces outside the block; cut contours are written in their ROIs’ order; a structure set with an ROI in another frame or none, an undeclared ROI, an unknown type, Contour Data not in threes, not finite, or too far, a Contour Offset Vector, or a Contour Slab Thickness is refused; PET is set to zero activity in the block less the kept brain, as the stored value of zero activity, with padding kept, a slice behind or below the block has no mask, and one that cannot be placed or stored, or compressed in a transfer syntax that no run decodes, is refused, while PET in RLE Lossless, JPEG Lossless First-Order Prediction, or JPEG 2000 Lossless is set to zero activity as native PET is; a verdict releases only the contours that the reviewed run wrote, and the contours’ digest changes with a contour’s values and type, with contours moved to another ROI or split otherwise, and not with how a value is written, and is null for contours that cannot be read; and in the defacing runs, the analytic head’s structure set is released with the option’s code, its outline and eyes below the kept brain’s floor exactly their parts outside the block, its outline above it, and a brain drawn out to the skull, exactly their parts outside the squares of the pixels that the released CT holds as air in the block, and more than the block’s plane leaves them, its brain and target unchanged, and a lens wholly in the block without contours, its two PET slices are released set to zero activity in the block, wholly below the cavity’s floor and around the kept brain above it, and unchanged outside it, and in a run that reviewed them as received, or without the head’s slices, they are held asface-verdict-on-other-contoursandface-verdict-on-other-pixel-data. ABINARYorFRACTIONALSegmentation’s segments are cleared in the block less the kept brain, only where a pixel lies in a segment and whatever a fractional value, a label map’s to its Pixel Padding Value of 8 or 16 bits, Segment Number 0 included, and each frame is placed by its own functional groups, each frame’s spacing its own, or by the shared ones alone, as is a segmentation without the Per-frame Functional Groups Sequence; aPALETTE COLORlabel map of 8 or 16 bits is cleared as aMONOCHROME2one is, and is not read for a text finder; a segmentation behind or below the block, or only in the kept brain, has no mask; each type is written cleared and checked, single bits packed eight to a byte keeping every other bit and the padding after the frames, while a bit written otherwise is found; single bits are written only by a defacer alone, not beside a finder or a reviewer’s regions, and are refused where signed, of more than one bit stored or sample, short of their frames, or given a value other than 0 or 1; frames of 5 by 7 bits, which start within a byte, are cleared and checked, keeping their neighbours’ bits, while a bit written otherwise is found, and must all be held; aBINARYsegmentation compressed, of an unknown type, of Bits Allocated other than its type’s,MONOCHROME1, signed, aBINARYorFRACTIONALone ofPALETTE COLOR, ofTILED_FULLframes, a label map without a Pixel Padding Value, with a range limit, one it cannot hold, or one that Segment Sequence does not describe, absent from its pixels too, without a position or spacing, with a position, orientation, or spacing in both the shared and a per-frame item, in every frame or one, with an empty Per-frame Functional Groups Sequence, with two positions, too few per-frame items, two shared items, zero spacing, non-unit or five direction cosines, or a huge or short position is refused; aFRACTIONALorLABELMAPsegmentation in RLE Lossless is cleared as a native one is; both SOP Classes name the Segmentation IOD, which a defaced frame holds; a defaced series gives a segmentation in its frame a block and none in another frame, and one over the head is written with its eyes’ pixels cleared and one behind the block as received; and in the defacing runs, the analytic head’s Segmentation of its body is released with the option’s code on a verdict on its segments sheet as written, its pixels in the block less the kept brain cleared and every other pixel as received, and in a run that reviewed it as received it is held asface-verdict-on-other-pixel-data, as is a cleared one whose review showed every frame as written through other previews but no segments sheet, or a sheet of all but one. Each frame of an Enhanced PET Image or Legacy Converted Enhanced PET Image instance of PET slices, with a Pixel Value Transformation of Rescale TypeUS, slope 2, and intercept -100, independent of a Real World Value Mapping in Bq/ml, placed by shared or per-frame groups, is set to zero activity as its slice is, stored value 0, not the display rescale’s 50, at its own zero activity where its mapping differs, 50 and 20 for frames of slope 2 and intercept -100 and of slope 0.5 and intercept -10, each zero by its mapping, keeping padding, and by two items, in Bq/ml and an SUV, that agree, and by an item of double-float first and last values mapped; a frame that cannot be placed, whose zero activity cannot be stored, whose mapping is a lookup table, has a slope of zero, maps no zero activity, has its first value mapped above its last or no last value, whose items disagree on zero or one of which maps that stored value to activity, that has no or an empty Real World Value Mapping functional group, a group in both sequences or none, a sequence an item short, another IOD, and a Positron Emission Tomography Image of two frames are refused, for each multi-frame PET IOD, while an Enhanced PET Image or Legacy Converted Enhanced PET Image instance in RLE Lossless or JPEG 2000 Lossless is set to zero as its native frames are; and in a run, the Enhanced PET image in a defaced frame is released set to zero, frame for frame as its slices are, while the collection’s Legacy Converted Enhanced PET, which no groups place, stays held. Around a kept target, a dose voxel is kept where its nearest pixel is kept for the target or its centre lies in the hull, beyond the slices too, the target’s own contours are written as received wherever they lie, between slices beyond their reach included, and an outline that crosses a target keeps exactly its parts in the squares of the pixels kept for it. A contour’s slab is found for a thickness, an offset, both, with offsets either way, its span holding all four readings, and an offset of aPOINTor a line along itself, and refused for each malformed value, a thickness without a plane, and an offset off its plane’s normal; the region whose spans meet the block agrees with spans sampled along their length for random points and slabs; a slab contour below the block whose span reaches it, beyond the slices’ reach, and one reaching it by its offset alone are cut by that region; a slab in the brain that each slice it reaches keeps, on one slice or two, is kept whole, one that reaches a slice that keeps no brain is cut by the whole block, one reaching a slice that keeps less loses just the squares that slice writes as air, and one beyond the slices’ reach, over two slices at one height, over slices whose grids differ, or over a tilted slice, is cut by the whole block; a slab contour below the block whose thickness alone, about its Contour Data, reaches it is cut, with its offset either way; for random rectangles, thicknesses, and offsets over three slices, no sampled point of what is written, at any height of each of its four readings, found from its values alone, has a nearest pixel written as air; for random blocks and readings tilted from a plane’s span and reaching beyond it, every point that a reading puts in the block lies in the grown region; a contour and a small hole in a plane tilted by 20°, their points written to 0.01 mm, are cut so that each, read along its own normal from its points as written, keeps every reading out of the block; one behind the block is kept whole, aPOINTwhose span reaches the block is removed, an open contour is written as its pieces outside the region, while one whose cut leaves a straight piece with a thickness is refused, and the closed contours of one plane are cut together, and refused where their values differ; a target contributes the hull of every reading of its valid slab, while a target whose slab cannot be placed holds the series, and an eye at its globe with a thin slab agrees, while one whose offset moves it 40 mm from its globe disagrees, as does one whose span runs from one globe’s reach to the other’s through a gap between them, though not where the two reaches meet. In a frame of two defaced series, each contour is cut by both blocks in turn, and PET and a segmentation’s pixels are set to zero activity or background where either block writes its CT as air; a structure set naming two frames is cut in its defaced frame and keeps its ROIs in the other as received, while one with an ROI in an undeclared frame, in a defaced frame without a block, or with a contour or a frame’s list of contour images referring to a defaced slice of another frame is refused; and in the defacing runs, with a second series of the head’s slices in its frame, the head’s PET slices are released as with one series, and its structure set, also declaring a second frame with an ROI where the block would lie, is released cut as with one, that ROI as received, while a structure set in its series whose contour’s slab crosses the block’s plane below the globes is released on the verdict for its drawn slab contours.
D-053: Recording an external statistical assessment#
Decision.
The statistical gate’s evidence is, for now, an assessment made outside the engine, recorded beside the QC pack of a run of the collection assessed, as
risk-assessment.json, a JSON document labelledpymedphys-deid-risk-assessment/2(pymedphys._dicom.deidentify.risk_assessment). It is QC material: it can describe the cohort and names its assessor, so it is written owner-only, never overwritten, and kept with the pack (D-016). A release report records only its opaque reference,R-and 32 random hexadecimal digits, and the gate’s outcome.The record holds what D-017 requires the assessment to state, each field required and none defaulted: the model’s name and version and its implementation’s name and version; the attacker’s assumed knowledge, and whether they know who is in the collection; either the reference population with its sampling assumptions, or why the assessment is within the release cohort, never both; the matching variables, at least one, each once, and how characteristics derivable from the pixel data were considered (MIDI-BP-07); the generalisation, the handling of missing data, the uncertainty, and the exclusions; how linked longitudinal records and earlier linked releases were accounted for; whether keeping machine identity would raise the risk above the threshold, which tells whoever reviews the record whether the omission that
public-releasemakes was needed (MIDI-BP-04, D-017); how the residual risk of the institutional identity that the policy keeps, such as the codes of local coding schemes, was assessed, and whether the assessment supports keeping it (MIDI-BP-05, D-017); whether re-identification from faces reconstructed from the images was among the channels assessed; the number of distinct subjects assessed, at least 1; the threshold, 0.09 or 0.05; the maximum per-subject re-identification probability, from 0 to 1; and who assessed it, and when, in UTC.The record binds the assessment to the QC pack, by its reference and the SHA-256 of its file; to the collection, by the SHA-256 of the sorted SHA-256 digests of the source files that the pack records, so that it depends on which files the run read, and how many copies of each, but not on their paths or order; to the policy, by the SHA-256 of the canonical JSON of the run’s release report’s
policysection and itsmethodsection without the method digest and the keyed digests of the reviewed lists and of the reviewed region rules; and to the reviewed ROI names and descriptors lists that descriptor cleaning applied and the reviewed region rules that Clean Pixel Data applied (D-037), by an HMAC-SHA-256, under 32 random bytes, of the SHA-256 of the canonical form of each list and of the rules, in that order, or of null for each not given. The run computes that digest, under a new salt, from the lists that its descriptor cleaning applied, as it read them, and the version of the rules that its Clean Pixel Data applied, the same that its readiness checks, and records it with its salt in its QC pack (format 18); the record copies both, so the lists and rules that it binds are those that the assessed run applied, never any that whoever records the assessment supplies. Recording refuses a pack that records no such digest, as a run without a release reporter writes; a release report that is not of its format or names another pack; a pack that records no source file, or a released, duplicate, or held instance without its source file’s SHA-256; and a pack that already has a record. Reading refuses a record that is not of its format, names a member twice, names another pack, or no longer matches the pack’s file or collection, or the lists’ digest and salt that the pack records.An assessor records an assessment with a command, kept off the
pymedphyscommand line until the first supported release as the tool’s other commands are, which publishes it aspymedphys dicom deidentify-assess, as the maintainer decided on 31 October 2026, and until then run aspython -m pymedphys._dicom.deidentify.risk_assessment_command PACK REPORT STATEMENT, wherePACKis the run’s QC pack directory,REPORTits publishedrelease-report.json, andSTATEMENTa UTF-8 JSON object, with or without a byte order mark, labelledpymedphys-deid-risk-statement/1, whose members are the record’s statements, by the same names, each required and no other:model, an object ofname,version,implementation, andimplementation_version;attacker, an object ofknowledgeandmembership_known;population, an object ofreferenceandsampling, or ofin_cohort, the form not taken left out or null;matching_variables, an array;pixel_derived,generalisation,missing_data,uncertainty,exclusions,linked_records,earlier_releases,device_identity,institutional_identity, andassessor, each text;facial_reconstruction, true or false;subjects, a whole number, andthresholdandmaximum_risk, numbers; andassessed_at, an ISO 8601 date and time with its UTC offset, which is recorded in UTC. A statement that is not UTF-8 JSON, names a member twice, holds a number that is not finite, lacks a member, has one that its format does not define, or carries another format, such as a record’s, is refused, and its messages name members but never a value, a member that the format does not define, or a path. It makes every refusal that recording makes, and with--checkmakes each of them and records nothing, since a record is never overwritten. Its summary gives the record’s and the pack’s opaque references, how many distinct subjects and matching variables were assessed, the threshold, whether the maximum probability is within it, and whether faces were assessed, and nothing that the statement says. The statement is QC material as the record is: the command neither moves nor removes it, and it is kept or disposed of as the pack is, never with the release.The statistical gate of a run given a record fails, by the first that holds, for no record (
no-assessment), another collection (other-collection), another policy (other-policy), other reviewed lists or region rules (other-lists), fewer or more subjects than the distinct subjects of the instances that the run releases (fewer-subjects,more-subjects), or a maximum probability above the threshold (above-threshold), and passes otherwise, a probability equal to the threshold passing. The threshold is the one that the assessment states; nothing yet selects the stricter one for a collection, so whoever reviews the record checks that the threshold suits the collection’s sensitivity. Its outcome is a reason code, never a value. Apublic-releaserun reports it in its release report’s readiness, with pixel and face review and the attestation, supplying the run’s collection, policy, lists, rules, and subjects (D-017).
Rationale. D-017 enables no estimator until one is selected and validated, and accepts a documented external assessment meanwhile, so the engine records and checks one rather than computing one. Binding the record to the collection and the policy is what makes “any change requires reassessment” checkable: a run of other files, or under another engine, policy, vocabulary, text finder, or list of safe private rules, finds another digest and fails the gate. The engine’s files and the text finder’s runtime are inputs of the method digest, so a new version of PyMedPhys, or of a library that the text finder names, needs a new assessment too, which is deliberate: either can change what is released. The keyed digests of the reviewed ROI names and descriptors lists, and of the reviewed region rules, differ under each run’s key, as D-024 sets, so a later run given the pack could never match the method digest of the run assessed, nor a policy digest that kept them, which would fail every gate of a later run with the same rules. The lists and rules are bound instead by their own digest, which any change to a decision or a rule changes. The rules are bound with the lists, rather than by a digest of their own, because they are a custodian’s reviewed resource of the same kind, whose change, like a list’s, needs a new assessment. They hold source names and values, and the rules manufacturers’ and model names, so that digest is salted, kept only in the confidential pack and record, and compared in constant time, and no release report carries it; a release report’s format is unchanged. The run records the digest, rather than recording taking the lists, because the lists that a run applied are known only to that run: a recorder given other lists, by mistake or after the custodian’s file was edited, would bind the assessment to lists that the assessed run never applied, and a later run with those lists would then pass the gate. The pack is the confidential material of the run that it binds, so the digest is kept there, and a pack written in an earlier format, which records none, is written again, as any earlier pack is. Requiring the count of subjects to equal the run’s, rather than to be at least it, catches an assessment that counted images, frames, or visits, which D-017 rules out. Recording the record beside the pack it assessed, rather than giving it to a run as a file of its own, keeps it with the confidential material that it describes and binds it to the pack as the attestation is bound. Whether faces were assessed is recorded so that an assessment that covers them can serve as the risk assessment reference that D-017 allows in place of a face verdict. The record carries the assessor’s statements without judging them: the engine checks that each is given, not that it is adequate, which is the assessor’s responsibility. The command reads the statements from a file, rather than from options, because they are paragraphs that an assessor drafts and reviews before recording; the file has a format of its own, so that a statement written for another set of statements is refused whole rather than read in part, and it carries no binding, which only the pack and the report give, so a record cannot be given again for another pack. A time is accepted at any UTC offset and recorded in UTC, since converting it by hand invites error, but never without one, which would leave the instant unknown. Because a record is never overwritten, a mistake, such as a count of images rather than of subjects, would otherwise need a new run of the collection, so
--checkmakes every check first.Tests. A record is written beside its pack, owner-only, with every field, and read back equal; each record has a new reference; a pack without one has none; reprs show no statement; each statement, each part of the model, the attacker’s knowledge and membership, and the population, given as both, neither, or half of a reference, is required; matching variables are at least one, each once, ignoring case and surrounding spaces; subjects are a whole number of at least 1; the threshold is 0.09 or 0.05 and the maximum probability a number from 0 to 1; the time is in UTC and not in the future; the gate passes a bound record within its threshold, at the threshold itself for both thresholds, and fails above it, without a record, for a collection with a copy fewer or more, a changed file, or none, for another preset, for another decision or value in a list, or a list left out or given empty, for another region in a rule, or rules left out or given empty, for fewer or more subjects, giving the first failure, and passes the same lists and rules read again; a later run with the same rules, whose report keys their digest under another key, passes every gate, and one with other rules fails the statistical gate; the lists’ digest is the specified HMAC, differs for another salt, and tells each list’s and the rules’ absence, emptiness, and content apart; a run’s pack records that digest of the lists and rules that its reporter checks, under a new salt for each run, binding the version of the rules that the transform applies and not a rule recorded since, and a run without a reporter records none; the record copies the pack’s digest and salt, whatever lists the release report records; the collection digest ignores order and counts copies; the policy digest is the same for another pack, the method digest, and any keyed digests of the lists or rules, and differs for any other component, such as an engine file; a report of another pack or not of its format, a pack that records no lists’ digest or one not of its format, a pack that binds no source file or has a released or held instance without its digest, and a second record, are refused, naming no path, both by recording and by binding without recording, which writes nothing and binds as recording does, and recording refuses a record that appears after its check without overwriting it; and a record for another pack, of another or an earlier format, such as format 1, which held no statement on institutional identity, with a field missing, added, or named twice, of a pack changed since, or whose lists’ salt or digest no longer matches the pack’s, is refused. The command records a statement equal to the same assessment given from Python, bound alike, leaving the release report unchanged, and a reference population with its sampling, text outside ASCII, a byte order mark, and a time at any UTC offset, in UTC; it refuses, quoting no statement, member, or path, a statement without each member, or a section without each of its own, naming each missing, one with members that its format does not define, a section that is not an object, a member named twice, one that is not UTF-8 JSON, nested too deeply, or of another format, including a record, a number that is not finite, each statement that is not text, each value nested deeper than Python recurses, with the message that an array nested twice gives, a model, attacker, population, matching variables, answers, or numbers that the record refuses, a time without its offset, outside the years 1 to 9999 in UTC, or in the future, a statement that cannot be read, and every refusal of recording;
--checkrecords nothing, gives the summary without a reference, refuses what recording refuses, including a pack that has a record, and leaves recording possible; the module’s example statement is recorded; its members are the record’s fields; argument errors quote nothing; and it runs as a module. End to end, apublic-releaserun of the synthetic corpus, attested with the attestation command and assessed with this one, makes a second run ready, naming the record that the command reported.
D-054: Checking the face block against HaN-Seg’s and PDDCA’s masks in CI and on DICOM exports#
Decision.
The face block that the finder finds (D-046) and the air that CT defacing writes (D-050) are checked against the reference masks of the HaN-Seg data set (Podobnik and others, Med Phys 2023, doi:10.1002/mp.16197), version 1.0 on Zenodo (doi:10.5281/zenodo.7442914): the planning CT and T1-weighted MR images of 42 head and neck patients, with binary masks of 30 organs at risk on each CT, among them each eye’s anterior and posterior parts, as NRRD files in one ZIP file. As the maintainer chose on 24 October 2026, the data set is test data that only CI uses, as MIDI-B is: only a GitHub-hosted runner of the
Face Block Checkworkflow (.github/workflows/face-validation.yml), started by hand, downloads it, from Zenodo, and checks it against the size and MD5 that the record gives. The runner reads it from its ZIP file without extracting it; it is never committed, cached, uploaded, or shipped, and only counts, codes, digests, versions, and the engine’s settings leave the runner.The check,
pymedphys._dicom.deidentify.face_validation, run aspython -m pymedphys._dicom.deidentify.face_validation_command hanseg, gives each CT volume tofind_face_blocksas a run gives it a series: as the CT Image instances of one series, one for each slice along the volume’s third axis, written in memory with the volume’s geometry and its values, rounded, as stored values in Hounsfield units, so that the finder applies the 400 mm head reach, the stack checks, and the check that air can be stored, as in a run. Each slice of a defaced series is then given toCtDefacer, which gives the pixels that a run writes as air. Its NRRD reader (nrrd.py) uses NumPy alone: it reads attached data, raw or gzip or bzip2 encoded, of integer or floating-point type, in left-posterior-superior, right-anterior-superior, or left-anterior-superior space and millimetres, and refuses anything else by why, quoting nothing of the file. Each mask is placed on the CT’s voxels by its own geometry, each of its voxels at the CT voxel nearest its centre, so a mask need not share the CT’s grid.Of each case, the check measures the finder’s outcome, by the reasons that the release report counts; where the series is defaced and both eyes’ masks are given, the distance from each globe found to the centroid of that eye’s voxels, whether the globes found were taken for the other side’s, the distance from the eyes’ voxel farthest from the nearer globe found to that globe, which a run compares with the 25 mm for an eye ROI (D-050), and the height of the eyes’ lowest voxel above the block’s inferior limit; the eyes’ own diameters, as those of spheres of their volumes, their separation across the axial plane, and the turn of the line between them; the share of each organ’s voxels written as air; and, where both eyes’ masks are given, what the finder saw in the same slices, as a run gives them to it, through
FaceFinder.inspect, from whichFaceFinder.blockdecides: the size of its voxels, how many balls of soft tissue it considered and kept as possible globes, the distance from each eye’s centroid to the nearest ball considered and to the nearest kept, that ball’s outcome and the two shares of its surround test, the greatest depth of soft tissue within 5 mm of the centroid against the depths at which the finder looks for a ball, the tests of the pair of kept balls within 5 mm of the eyes (side by side, bone lateral and superior to each, the head’s fills behind and in front, and the cranium’s test), how many other pairs passed the tests of a pair and where their balls lie from the eyes, the test that each ball lies just under the skin, for the pair at the eyes and for each other pair that passes the other tests (the depth to air in front of each ball, the length through lower values before it, whether bone lies before it, and on which side both balls are open to air), and the shares of soft tissue, fat, air, bone, and other values about each kept ball, separately for those at the eyes and the others, each counted by the case’s outcome, so that a refusal can be traced to the test that gave it. Its summary,face-validation.json, labelledpymedphys-deid-face-validation/3, and the same counts as CommonMark,face-validation.md, count the cases by outcome and format and the measures in fixed bins, and give the data set’s citation, DOI, and licence, its file’s size, MD5, and SHA-256, the software’s versions, and the engine’s settings; they name no case and give no value. A case that cannot be read is counted by why, and one whose measuring raises anything else by the exception’s type and the place in the code that raised it, never its message; a crash outside a case is reported by.github/scripts/run_redacted.pyin the same way.As the maintainer allowed on 1 November 2026 for public data whose licence explicitly permits its use, the same check runs against the Public Domain Database for Computational Anatomy (PDDCA), version 1.4.1 (Raudaschl and others, Med Phys 2017, doi:10.1002/mp.12197): the planning CTs of 48 head and neck patients of the RTOG 0522 trial, with expert masks of the brainstem, chiasm, mandible, optic nerves, parotids, and submandibular glands, re-hosted on Zenodo in three ZIP files (doi:10.5281/zenodo.19657912, doi:10.5281/zenodo.19658040, and doi:10.5281/zenodo.19658102), whose records give its licence as CC BY 3.0, as first distributed. Only a GitHub-hosted runner of the
Face Block Check on PDDCAworkflow (.github/workflows/face-validation-pddca.yml), started by hand, downloads them, and checks each against the size and MD5 that its record gives;pymedphys._dicom.deidentify.face_validation_pddca, run aspython -m pymedphys._dicom.deidentify.face_validation_command pddca, also pins each file’s SHA-256 and refuses a file that differs. It reads them as the HaN-Seg check reads HaN-Seg, with no masks of the eyes, so it measures each case as that check measures a case without eye masks; and, since each optic nerve runs back from its globe, where the series is defaced and both nerves’ masks are given, the distance from each globe found to the anterior tip of its side’s nerve, the nerve’s voxel farthest towards the patient’s anterior, how far that tip lies behind the globe along the block’s anterior, and whether the globes found are nearer the other side’s tips. Its summary, labelledpymedphys-deid-face-validation-pddca/1, and its page, which share the HaN-Seg check’s counts and add those of the optic nerves in fixed bins, name the data set, its citation and licence, and each file’s DOI, size, MD5, and SHA-256, and name no case and give no value. TCIA now distributes the trial’s images under controlled access, since they could be used to reconstruct a face, so the check, like the HaN-Seg check, renders nothing and writes only counts. Its cases are held-out evidence: the finder’s settings were not set from them and are not to be tuned to them.TCIA’s head and neck collections are not used in CI, PDDCA’s separately licensed re-distribution aside. TCIA distributes those whose images could show a face under its limited-access licence, which strictly prohibits generating representations of the face for facial recognition or re-identification (section 3.2), prohibits reconstructing them without approval for purposes unrelated to re-identification (3.3), and prohibits giving a third party access without the licensor’s written consent (4), as a hosted runner would have.
As the maintainer also chose on 24 October 2026, the same engine code is checked, with no render, on DICOM files that a person may process, such as their own planning system’s exports, on their own machine:
pymedphys._dicom.deidentify.face_validation_dicom, run aspython -m pymedphys._dicom.deidentify.face_validation_command dicom, finds the files below a directory as a run’s discovery does, reads each into its record, and gives the records and files tofind_face_blocksandfind_dose_blocksas a run does, a file that changes once read counting as one that can no longer be read. Of each series of CT Image, Enhanced CT Image, or Legacy Converted Enhanced CT Image, it measures the finder’s outcome by the reasons that the release report counts, how the series is stored, its spacings, two slices within a micrometre of one position counting as no spacing, and whether air is stored, a multi-frame instance’s frames placed and read in Hounsfield units as the finder reads them; how many phases the run parts its slices into, how many of a series of several find no eyes, and, where two or more phases find a block, whether or not they agree, the greatest distance between one globe’s centres in two phases, which the run compares with D-050’s placeholder 8 mm, every phase’s block being found before they are compared so that a series whose phases disagree is measured too; for a series with a block, defaced or held for a target or an eye, against the globes of the phase that its farthest point lies farthest from, each eye ROI that the run checks in the structure sets that it searches for the series: the distance from the globe on the side that its name gives, or for a name that gives none from the nearer globe to each of its contours, to the centroid of its closed contours weighted by their areas, whether it is nearer the other side’s globe of any phase, the distance from its farthest point to the nearer globe, which the run compares with the 25 mm eye reach, and the height of its lowest point above the block’s inferior limit; each target, by whether the run keeps it in the block, holds the series for it and why, or neither, as the run judges it, and the clearance from the block of one in the series’ frame that does not reach it, the distance from the convex hull of its points to the block, which is found in the plane of each point’s distance ahead of the block’s vertical plane and height above its inferior limit, at a hull vertex or at an edge’s nearest point to the block’s corner; and for any other series, whether those structure sets hold an eye ROI. Of each RT Dose with pixel data that the run sets to zero in a defaced frame or holds for one, it counts the outcome, with the greatest stored value thatRtDoseDefacerwould set to zero as a fraction of the grid’s greatest, which the run compares with D-051’s placeholder 5%, each frame given to it by the run’s own cleaner,black_out, so that Pixel Data that a run refuses, such as a field of more bytes than its frames and one byte of padding, is counted as held, as a run holds it; of each RT Structure Set that the run cuts or holds for a defaced frame, the outcome and the ROIs thatcut_contourswould cut, by RT ROI Interpreted Type, a value outside its defined terms counting asother; and the RT Plans that name a defaced series’ frame. It decodes compressed Pixel Data as a run decodes it, by the plugin pinned to its transfer syntax and, where that plugin runs native code, in the decoding child (D-037), so it measures air in a compressed series and the dose in a compressed RT Dose; a series with a slice that does not decode has no air measure and the outcomeundecodable-pixel-data, as a run finds it, and an RT Dose that does not decode is counted as held. Its summary, labelledpymedphys-deid-face-validation-dicom/6, and its page, written as the HaN-Seg check’s are, hold only counts, codes, bin edges, versions, and settings: no UID, name, date, path, ROI name, or value. A series, RT Dose, or RT Structure Set whose measuring raises is counted by the exception’s type and place, the command reports anything else that the check raises in the same way, and pydicom’s warnings and log records are redacted. This project’s sessions never run it on real data or read its inputs.The counts are evidence bearing on placeholders without validating them: the HaN-Seg check’s on two of D-050’s, the 5 mm margin and the 25 mm eye reach, and on the finder’s yield on clinical CT; the PDDCA check’s on the finder’s yield on clinical CT and, as anatomical corroboration rather than a measured error, on where it places the globes, as held-out evidence; the DICOM check’s on those two, D-050’s 8 mm phase reach, D-051’s 5% dose fraction, and the finder’s yield on clinical CT as a person’s exports hold it. None bears on the 30 mm cavity floor or on how much of the brain defacing keeps: neither HaN-Seg nor PDDCA marks the brain, and their brainstems, chiasms, and HaN-Seg’s pituitary are no reference for either, and the DICOM check measures no brain ROI. Changing a setting, or enabling the option (D-033), is a decision of its own, and neither check claims a result.
Rationale. The finder’s tests use an analytic head, and the phantom check a phantom whose orbits hold no globes, so neither shows how the finder does on patients’ anatomy: globes of other sizes, fat about them, eyes turned or closed, immobilisation masks, and scanners’ noise and reconstruction. HaN-Seg’s planning CTs come with masks of each eye curated from experts’ manual annotations, which place the globes independently of the image, and the data set is openly downloadable. Its Zenodo record and the licence in its ZIP file give CC BY-NC-ND 4.0, while its README names CC BY-ND 4.0, so the stricter is followed: the project uses it non-commercially, to test open-source software, shares no copy of it, adapted or not, and gives the attribution with the counts. Its images are of real patients, published de-identified, so the project treats them as real patient data, as it treats MIDI-B’s synthetic identifiers as real: nothing of them leaves the runner but counts that name no value. NRRD volumes are written as a run’s series because the finder’s checks of a series are part of what is tested, and masks are placed by their geometry rather than assumed to share the CT’s grid. PDDCA adds cases on which the finder’s settings were never tuned; it marks no eyes, but the anterior tip of a complete optic nerve mask is where the nerve meets its globe’s back, roughly a globe’s radius behind its centre, so a globe found far from its own nerve’s tip, or nearer the other’s, flags a discrepancy, from a globe placed wrongly or from a nerve mask that is incomplete or inaccurate, without a reference placed from the image. The measures corroborate the globes found and do not measure their error: a centre several millimetres from the true one can keep a radius-like distance and depth on the correct side. Counts in fixed bins, rather than statistics such as a median or a maximum, each of which is one case’s value, give no case’s value. Nothing here tests whether a defaced face can be recognised, which needs renders and a recogniser. HaN-Seg’s masks include no targets, so defacing around a target in the block and the hold for one beyond the slices, the eye ROI hold as planners draw and name eyes, RT Dose defacing, and contour cutting are checked on planning exports instead, which hold them all; that check renders nothing, so it needs no permission to reconstruct a face, and reads the files where they lie, so nothing of them leaves the machine but counts. A planner’s eye ROIs are compared with the globes found, rather than with masks of the image, because they are what a run compares; their centroid is weighted by contour area so that a globe drawn with more points on one side is not pulled towards them. A target’s clearance is the distance from the hull, the region that a run treats as the target, since a minimum over its points alone overstates it where a hull edge passes the block’s corner.
Tests. The NRRD reader reads each type, byte order, and encoding into the values written, places each voxel by the space directions in left-posterior-superior and right-anterior-superior space on an off-centre oblique grid, turns the y axis of left-anterior-superior space, keeps a segmentation’s layers last, reads other spellings of fields and data in several compressed streams, and refuses each malformed, detached, unsupported, too large, short, or long file by why, before reading the data of one too large, quoting nothing of it. On the analytic head written as HaN-Seg’s cases, the check measures the globe errors, eye reach, and the eyes’ height above the inferior limit against the block that the finder finds from the slices directly, and the eyes’ diameters and separation from the masks’ voxels; it finds the front of each eye and a lacrimal gland written as air, the share of the back of each eye in front of the block’s plane, and the lips and brainstem not; a CT in right-anterior-superior space, raw, with masks cut to their boxes and on a finer grid, gives the same measures, and one stored as coronal slices the same outcome; a head without eyes is counted as
no-eyes, eye masks moved 30 mm aseyes-disagree-with-rois, and eyes named for the other side as swapped; a truncated, missing, four-dimensional, or non-finite CT, and masks that cannot be read, are counted by why, and a CT whose values are not in Hounsfield units as without air; a case that raises is counted by its type and place, without its message; what the finder saw shows each globe of the head kept with its pair passing every test, no ball or soft tissue at the eyes of the head without them, the globes of eyes moved 30 mm as another pair beside them, eyes named for the other side tested as the same pair, and another head in view as another pair; the finder’s inspection of the analytic head shows every ball considered, deepest first, each kept by its surround test’s shares and each not tested within a kept ball, every two kept balls tested as a pair, the depth near each globe about its radius, each test’s outcome for a head without an eye, without bony orbits, facing back, upside down, or beside another, and gives the same block or refusal as the finder; the summary holds only integers, bin edges, and settings, and is the same each time; the page is CommonMark; and the command writes both files, prints the page, and refuses an existing output directory, a file that is not a ZIP file, and a ZIP file without a case, without quoting a path. On the analytic head written as PDDCA’s cases, with rods for optic nerves from just behind each globe to the orbit’s apex, in two ZIP files, the PDDCA check finds each case by its directory and reads no landmarks; measures each globe’s distance to its nerve’s anterior tip and the tip’s depth behind it against the block that the finder finds from the slices directly, the brainstem and nerves not written as air; counts nerves named for the other side as swapped, and a case without both nerves, a head without eyes, and a case without a CT as not measured against the nerves; holds no case’s name or value and is the same each time; refuses too few files, or a file that differs from the one pinned, without quoting its path; and gives the page as CommonMark, which the command writes and prints. On five synthetic cases of the analytic head written as planning exports, the DICOM check finds a head defaced, one without eyes, one with a target in its block and another in it beyond its slices, which holds it, one with an eye ROI 40 mm from its globe, and one defaced around a target in its block, as a run does; measures each eye ROI’s globe error, reach, and height above the inferior limit against the block that the finder finds from the slices directly, with the centroid weighted by each circle’s own area, reads its side from its name, splits an eye ROI that names no side by the nearer globe, and finds a right eye drawn at the left globe swapped; counts a target behind the block as clear at its distance behind the plane, one in the block as kept, one beyond the slices as such, and one behind it or in it with a contour of a slab thickness or offset as not placed, as the run holds it, with no clearance, though one whose values are empty as clear or kept; finds RT Doses of 3% and 30% of the grid’s greatest in the block set to zero and held, and one of 3% whose Pixel Data has two bytes more than its frames held, as the run’s cleaner refuses it; counts each defined term of RT ROI Interpreted Type as itself and any other value asother; finds the body and eye ROIs cut and the rest not, a target kept in the block included; counts RT Plans in the defaced frame, a DICOMDIR refused, and a text file not read; finds a target’s clearance where a hull edge passes the block’s corner, closer than any vertex; counts a series that raises by where; measures a series and its RT Doses in RLE Lossless or JPEG 2000 Lossless as it measures the native files, other than how they are stored, gives a compressed series with a slice that does not decode its outcome without an air measure, and counts a compressed RT Dose that does not decode as held; holds only integers, bin edges, and settings, and nothing of the files, the same each time; and its command writes both files and refuses a directory without a CT series or one that cannot be listed, and reports a crash, without quoting a path or message. It counts each series without repeated positions as one phase; on five series of phases, finds two time points of the head moved a little defaced, two whose globes lie 12 mm apartphases-disagreewith the spread of both phases’ own blocks, two acquisitions with one below the eyes defaced with one phase without eyes, slices that nothing partsrepeated-positionsand not parted, and two time points of one Enhanced CT Image instance defaced, with its storage, spacing, and air measured; measures an eye ROI drawn at one phase’s globes against the other’s, whose globes lie farther, and finds an eye swapped against either phase swapped; counts two slices half a micrometre apart as no spacing; finds the globe spread of each globe against itself alone; bins the spreads with an edge at the phase reach; reports no source values.
D-055: Decoding the frames that pydicom’s GDCM plugin refuses#
Decision.
pydicom 3.0.2’s GDCM plugin raises, before GDCM sees the frame, for JPEG Extended (1.2.840.10008.1.2.4.51) with Bits Stored other than 8, for JPEG-LS Lossless and Near-Lossless (1.2.840.10008.1.2.4.80 and .81) with Bits Stored 6 or 7, and for JPEG-LS Near-Lossless with Pixel Representation 1 and Bits Stored below 8. Frames of those kinds, chosen by those attributes, are pinned to a decoding plugin of the engine’s own,
imagecodecs_plugin, which decodes JPEG with libjpeg-turbo 3 and JPEG-LS with CharLS, each through imagecodecs, whatever GDCM would do; every other frame keeps the plugin of its transfer syntax (Architecture item 2). So each kind of frame still has one decoder, whatever else is installed. Bits Stored or Pixel Representation that cannot be read leaves the transfer syntax’s own plugin, whose checks then refuse the frame.The plugin has the form of pydicom’s decoding plugins, so pydicom applies to its frames what it applies to every plugin’s: the sign of JPEG-LS samples, Bits Stored, and conversion of YBR_FULL and YBR_FULL_422 to RGB where Clean Pixel Data or a preview asks for RGB. It gives the samples as the codestream holds them, with no conversion of colour space of its own, and colour with the samples of each pixel together. imagecodecs gives samples of at most 8 bits in one byte each, so the engine decodes each frame by its index, which has pydicom widen them to Bits Allocated before correcting their sign: JPEG-LS at 6 or 7 bits may be held in 16-bit samples (PS3.5 Table 8.2.3-1), as the MR Image Module, for one, requires.
It is never added to pydicom’s own decoders, so installing PyMedPhys changes nothing that pydicom decodes elsewhere. The decoding child adds it to a decoder object of the engine’s own, and decodes with it only there: checking frames, comparing a written frame with its source’s, Clean Pixel Data, and also the QC pack’s previews, which for these frames send each frame’s codestream to the child and check what it sends back as Clean Pixel Data checks it, rather than decoding in process. The engine’s process never imports imagecodecs. Whether the child can decode each transfer syntax with it is asked of the child once per process; where imagecodecs is not installed, lacks the codec, or the child cannot be started, the instance is
no-decoder.The
userextra declaresimagecodecs>=2025.11.11, its first release with wheels for every supported Python; JPEG needs it built with libjpeg-turbo 3.0 or later, the first that decodes 12-bit lossy JPEG, as the wheels checked, from 2025.11.11 to 2026.10.10, are.As the maintainer decided on 7 October 2026, each decoder is licensed at least as permissively as PyMedPhys’s Apache License 2.0, with no GPL-3.0: imagecodecs is BSD-3-Clause, libjpeg-turbo is under the IJG, BSD-3-Clause, and zlib licences, and CharLS is BSD-3-Clause. imagecodecs’s wheels also bundle libraries for codecs that the engine never loads, under permissive licences, and GCC’s OpenMP runtime, libgomp, under the GPL version 3 with the GCC Runtime Library Exception, which only its zfp and SZ3 codecs link; NumPy, SciPy, and scikit-learn, which the
userextra already installs, bundle GCC runtimes under the same terms.libjpeg-turbo passes on no warning through imagecodecs, so a JPEG frame whose entropy-coded data ends early but is still followed by EOI decodes, as it does with GDCM; Architecture item 2’s checks of each codestream’s markers apply to these frames as to any other.
Rationale. Without a decoder, those frames are sequestered as
undecodable-pixel-data, so no 12-bit lossy JPEG image, which is what JPEG Extended’s 12-bit process is for, and no 6- or 7-bit JPEG-LS image could be released. pylibjpeg-libjpeg decodes them, but under the GPL version 3. pyjpegls (MIT, with CharLS) decodes JPEG-LS but not JPEG, and publishes no wheels for Python 3.14; Pillow decodes neither. imagecodecs alone covers all three kinds under permissive licences, with wheels for Linux, macOS, and Windows, and its libjpeg-turbo and CharLS are widely used decoders: CharLS is also the JPEG-LS codec within GDCM and DCMTK. Pinning by kind, rather than moving JPEG and JPEG-LS to imagecodecs, leaves every frame that GDCM already decodes, and the evidence for it, unchanged. A decoder object of the engine’s own, rather than pydicom’s registry, keeps the plugin from deciding anything that pydicom decodes in a user’s own code. Previews are decoded in the child because libjpeg-turbo and CharLS are native libraries that a malformed codestream could make end the process, and pydicom in the engine’s process does not hold the plugin.Tests. Every image is coded by an encoder in the test helpers, never by the decoder under test: 12-bit JPEG Extended whose 8 by 8 blocks each hold one value, which decodes exactly, and JPEG-LS by an encoder written from ITU-T T.87, with regular and run modes, near-lossless coding, and one scan per colour component, which also gives each sample as T.87 reconstructs it. Each kind, unsigned and signed, monochrome and RGB, at 2 to 12 bits and NEAR 0 to 3, is pinned to imagecodecs, refused by pydicom’s GDCM plugin in a process of its own, found sound, and decoded to the samples coded, exactly, in two’s complement where signed, and within NEAR of them; neighbouring kinds keep GDCM; multi-frame images decode each frame and frames other than Number of Frames are refused; a damaged JPEG-LS scan is
undecodable-pixel-data; frames of other samples are not the same pixels; without imagecodecs, where the child lacks the codec, and where the child cannot be started, the instance isno-decoder, the last not remembered; libjpeg-turbo before 3.0 does not decode 12-bit JPEG; pydicom’s own decoders never hold the plugin; the engine’s process never imports imagecodecs; a kept-compressed image is written with its codestream; Clean Pixel Data blacks out and writes the decoded frames; and a QC preview decodes in the child and shows what a native copy shows, or says that a frame cannot be decoded.
D-056: Evaluating and tuning the text detector on images with and without burned-in text#
Decision.
As the maintainer chose on 31 October 2026, the text detector of the Clean Pixel Data Option (D-037) is evaluated, and its model, parameters, and renderings are chosen, on a corpus of six tiers of images with and without burned-in text, across the IODs in the release scope (Scope). Missed text and false positives are measured on the same images, against acceptance criteria set before any tuning run, and the detector chosen is confirmed once on data never used to tune it. Of the evaluation, the evaluation library is built, in
pymedphys._dicom.deidentify.text_evaluationand itstext_evaluation_*modules, among them the inventory’s counts, which no job runs yet, with theText Detector Evaluationworkflow (.github/workflows/text-detector-evaluation.yml), started by hand, whose patients’ job measures T3’s collections from NCI’s Imaging Data Commons, the seven taken from TCIA among them, and the folders of the pinned archives, with T4’s text burned into them, and whose phantoms’ job reports T1’s synthetic phantoms and T2’s phantom collections in full, with crops, as the Text Detector Check’s guide describes; the rest is delivered in the parts listed below, each a pull request of its own, and until the last of them is adopted the detector stays as D-037 describes it. Every instance that the option cleans is still held for review, whatever the evaluation finds (D-037, D-048).Images of real patients, public collections among them, are real patient data, as D-054 treats HaN-Seg’s: but for T6’s, which are read only on the maintainer’s or another person’s own machine, only a GitHub-hosted runner of a workflow started by hand downloads them, reads them where it downloaded them, and burns text into them only in memory, and only counts, codes, digests, versions, bin edges, settings, and the detector’s method leave the runner, but for the results by case set out below for the openly licensed collections in NCI’s Imaging Data Commons and the seven taken from TCIA. Nothing of them is committed, cached, uploaded, or shipped, and no session of this project opens one. Synthetic images and images of phantoms, which show no patient, are not under that rule, which still governs every collection of real patients’ images and every image derived from them: they may be used, viewed, and, where their licences allow, published, as T2’s results are. As the maintainer decided on 1 November 2026, a collection whose licence explicitly allows what the evaluation does with it is added without asking him, and any other only with his approval. The licences that so allow it are CC BY 3.0 and 4.0, CC BY-NC 3.0 and 4.0, CC0, the Open Data Commons Public Domain Dedication and Licence, and the National Library of Medicine’s terms and conditions as NCI’s Imaging Data Commons names them; the harness reads each series’ licence and DOI with it and refuses a series whose licence is not among them. Either way its licence and terms are read from the collection’s own page before it is used, as D-054 read HaN-Seg’s licence and TCIA’s limited-access licence, and where two sources give different terms, such as a distributor’s metadata and the collection’s page, the stricter is followed until they are reconciled.
The corpus has six tiers:
T1, synthetic frames. An extension of the tests’ generator of burned-in text (
tests/dicom/_synthetic_text.py) makes frames from a seed, with each piece of text’s ink as an exact mask. It varies, as strata of the counts: the font, among them the existing 5 × 7 bitmap font, Pillow’s built-in bitmap font, and anti-aliased sans-serif, serif, and monospace fonts; the text’s height, from 5 to 40 pixels, and the same height in millimetres at the frame’s spacing; its contrast against the local background and noise, from barely visible to saturated; its polarity, brighter or darker than the background; its style, solid, outlined, drop-shadowed, on an opaque box, or semi-transparent; its orientation, at 0, 90, or 270 degrees; its position, in air at a corner, over tissue, or across the body’s edge; its content, such as names, identifiers, dates, single letters such asL,R, andA, and scale bars with numbers; and the background, the existing geometric phantoms and textures modelled on bone, air cells, and noise, at several spacings and at 512, 768, and 1024 pixels a side. As the maintainer chose on 31 October 2026, Pillow renders the text, in the test and evaluation dependencies only, and the anti-aliased fonts are twelve faces under the SIL Open Font License 1.1: Source Sans Pro, Lato, Noto Sans, Source Serif Pro, and Fira Mono, each regular and bold, and FiraGO and Space Mono, regular, which the tests and CI take from wheels on the Python Package Index, each used only where the wheel and the font in it have their pinned SHA-256; no font file is committed or ships in the package.T2, viewable phantoms. As the maintainer chose on 31 October 2026, public phantom collections on TCIA serve as negatives that can be viewed, across the scanners and protocols of several vendors: CC-Radiomics-Phantom-3 (doi:10.7937/tcia.2019.j71i4fah) and RIDER PHANTOM PET-CT (doi:10.7937/K9/TCIA.2015.8WG2KN4W), each under CC BY 3.0. MRI-DIR (doi:10.7937/K9/TCIA.2018.3f08iejt), under CC BY 4.0, holds a physical phantom of porcine meat,
MRI-DIR-zzmeatphantomin the Imaging Data Commons, which, as the maintainer chose on 6 November 2026, is not used, since the evaluation uses no porcine phantom. MRI-DIR’s computational subjects are synthetic MR images derived from real patients’ scans, so they are treated as real patients’ images and only counted, as T3’s are. The evaluation’s workflow downloads these collections on its runners and, unlike a collection of real patients’ images, publishes, for the phantoms alone, their results by case and a crop of every region that the detector finds in them, which is a false positive unless the crop shows real text, as workflow artefacts with each collection’s citation, DOI, and licence and a note that the crops are cut out of the images and windowed, in a report labelledpymedphys-deid-text-detector-phantom-report/1. Before it publishes a crop or a case’s result, the workflow checks that the series is on an allow-list fixed in the code, of the phantoms’ series by collection, Patient ID, and Series Instance UID, and that it downloaded the series as part of that collection. The list holds every series of CC-Radiomics-Phantom-3, RIDER PHANTOM PET-CT, STEEV, and VICTRE, collections whose every subject is a phantom, and none of MRI-DIR’s. Any other series is only counted, as a real patient’s image is, so that no image of a patient, or derived from one, can be published by mistake. T2 also holds, as the maintainer chose on 1 November 2026, while preferring a variety of patients’ images where they can be had, the CT and the five DRRs of the STEEV head phantom, whose DRRs carry no Burned In Annotation and no overlay planes and show no text, and which add to the few frames without text that RT Image has. They enter CI only from the published Zenodo record ofsteev-head-phantom-1.0.0, checked against the SHA-256 of its ZIP file,4cc4f34e874b6da0f2d63092ccd20a2769e3f58960fd26e532d1e3e760747228, and never from another copy, so they wait on that record’s publication. It holds too the computer-simulated breast images of VICTRE (victrein NCI’s Imaging Data Commons, CC BY 3.0 there), which show no patient, as negatives that can be viewed.T3, real images without text. Images of the IODs in scope from approved collections, used on CI’s runners alone and for counts alone, but for the results by case set out below for openly licensed collections: HaN-Seg’s CTs and MRs, which the Text Detector Check already reads (D-037); and, as the maintainer approved on 31 October 2026, the images of MIDI-B’s validation and test sets (D-018) for which its answer key records no burned-in text, and seven collections on TCIA, chosen for what those lack, such as PET from several sites, cone-beam CT, other body sites than the head and neck, and children: Pancreatic-CT-CBCT-SEG (doi:10.7937/TCIA.ESHQ-4D90), Lung-PET-CT-Dx (doi:10.7937/TCIA.2020.NNC2-0461), and Pediatric-CT-SEG (doi:10.7937/TCIA.X0H0-1706), each under CC BY 4.0; 4D-Lung (doi:10.7937/K9/TCIA.2016.ELN8YGLE), ACRIN-NSCLC-FDG-PET (doi:10.7937/tcia.2019.30ilqfcl), and Anti-PD-1_Lung (doi:10.7937/tcia.2019.zjjwb9ip), each under CC BY 3.0; and NSCLC-Radiomics (doi:10.7937/K9/TCIA.2015.PF0M9REI), under CC BY-NC 3.0. Each collection’s citation, DOI, and licence are given with its counts, as its TCIA page and TCIA’s data usage policy ask. A collection too large for the runners is read in shards, or as a sample of its cases drawn by a rule fixed in the code, as the split is, planned from the inventory’s counts. The seven are read from the Imaging Data Commons’ copy of them, by their identifiers there (
4d_lung,acrin_nsclc_fdg_pet,anti_pd_1_lung,lung_pet_ct_dx,nsclc_radiomics,pancreatic_ct_cbct_seg, andpediatric_ct_seg), and named by their TCIA collection names: on 7 November 2026 its index (idc-index-data 25.0.5) held, for each, the same image series as TCIA’s public listing, 13,220 in all and none on one side alone, under the same licence, and some of CI’s runners cannot reach TCIA. Under his decision of 1 November 2026 on openly licensed data, T3 also takes these collections from NCI’s Imaging Data Commons, which is their source for CI, by their identifiers there, with the licences that its metadata gives, each to be confirmed from the collection’s own page:eay131; the Cancer Moonshot Biobank’scmb_lca,cmb_crc,cmb_mel,cmb_mml,cmb_brca,cmb_ov,cmb_pca, andcmb_aml;covid_19_ny_sbu,covid_19_ar,varepop_apollo,cmmd,ea1141,advanced_mri_breast_lesions,remind,prostate_mri_us_biopsy,b_mode_and_ceus_liver,psma_pet_ct_lesions,acrin_contralateral_breast_mr, andpseudo_phi_dicom_data, less any image that its answer key records as holding burned-in text, under CC BY 4.0;tcga_blca,tcga_ov,lidc_idri,cbis_ddsm, andsoft_tissue_sarcoma, under CC BY 3.0; andmidrc_ricord_1candbreast_cancer_screening_dbt, under CC BY-NC 4.0. They add many scanners’ CT and MR, PET of a second tracer, CR, DX, XA, RF, NM, mammography and tomosynthesis, ultrasound, and Secondary Capture, among them digitised film. Under his direction of 6 November 2026 that public human patients’ data is to be preferred and searched for deeply, T3 also takes, under CC BY 4.0, the brain and head MR ofvestibular_schwannoma_mc_rc(doi:10.7937/hrzh-2n82), from four makers’ scanners and defaced by its curators,upenn_gbm(doi:10.7937/TCIA.709X-DN49), andvestibular_schwannoma_seg(doi:10.7937/TCIA.9YTJ-5Q73), whose patients the first collection shares in part: TCIA’s page for it gives 58 of its patients as the second’s, under the same Patient IDs, with other studies and series, so a patient of both is one subject, named in a namespace that the two collections share, which takes one part of the split and which the bootstrap resamples as one; and, ofacrin_flt_breast,tcga_brca,tcga_coad,tcga_kirc,tcga_luad,tcga_lusc,tcga_prad, andtcga_ucec, under CC BY 3.0, andcptac_aml,cptac_cm,cptac_luad,cptac_pda,cptac_stad, andcptac_ucec, under CC BY 4.0, only their Secondary Capture, Nuclear Medicine, and ultrasound images, which add screen captures, PET summary screens, NM, and ultrasound from other makers, since their CT, MR, and PET add little beside the other collections’. Each licence was read on 6 November 2026 in TCIA’s licence API, which gives each of these collections that licence alone, and in TCIA’s public listing of each series, which agrees with IDC’s. Screen captures, PET summary screens, and ultrasound commonly carry burned-in text, so the frames of those fourteen collections are taken with their text unknown, as T6’s are: a region found on one as received is counted apart from the false positives, and the text that T4 burns into them measures missed text. TCIA’s licence API also lists a restricted portion, of head images, for several Cancer Moonshot Biobank collections; TCIA’s public listing gives every image series of those collections that IDC holds, among them the series of the head, brain, and neck, as CC BY 4.0, so that portion is in neither source, and the collections are taken as before. As the maintainer chose on 6 November 2026, T3 also takes, from Zenodo, five records of openly licensed human DICOM that fill what no collection above holds, each counted only: the defaced head CT angiography of three clinical centres, from Toshiba, Siemens, Hitachi, and GE scanners (doi:10.5281/zenodo.15697196); the bone scintigraphy and SPECT/CT of patients with psoriatic arthritis, whose Nuclear Medicine images are multi-frame (doi:10.5281/zenodo.15549552); the dental cone-beam CT of the Dens Invaginatus record, with its screen captures, whose text is taken as unknown (doi:10.5281/zenodo.16738223); and the cardiac and knee MR of consented volunteers on a 0.55 T scanner, stored as Enhanced MR Image Storage (doi:10.5281/zenodo.23089164 and doi:10.5281/zenodo.23964089), each under CC BY 4.0. Each archive is pinned by its size, the MD5 that its record gives it, by which its file is found, since some records name an archive by what may be a patient’s initials, and the SHA-256 of its central directory, which gives every member’s CRC-32; the runner reads each archive in place, over HTTP ranges, takes whole leaf folders, which in these records hold a series or an examination, in an order fixed by a digest, up to a number and a size, and writes each member under a digest of its name, never the name itself. T3 also takes, from the University of Sydney’s research data store, the RT Images of the BRAVEHeart trial of breast radiotherapy (doi:10.25910/7by0-vf89), under CC BY 4.0 and counted only: the kV images of a Varian On-Board Imager and the DRRs of Varian’s ARIA, the first real RT Images found under an open licence. Their text is taken as unknown, since nothing shows that they were curated for burned-in text. The trial’s archives also hold CT, RT Plan, and RT Structure Set objects and Varian’s own image formats, which are not taken: each archive is pinned by its path, its size, the SHA-256 of its central directory, and the digests of the leaf folders that held RT Images when it was pinned, so that no other folder is fetched, and only members whose SOP Class is RT Image Storage are written.fdg_pet_ct_lesions, which the Imaging Data Commons lists as CC BY 4.0 and TCIA’s page has shown as restricted, joins only once its open licence is confirmed. No openly licensed collection holds Enhanced CT or PET or Legacy Converted Enhanced images, only the volunteers’ records above hold Enhanced MR, and only BRAVEHeart holds RT Image, whose frames are counted only and whose text is unknown, so RT Image with text known comes only from T2 and T6, and the runner converts single-frame CT, MR, and PET series of these collections, in memory, with a converter of the evaluation’s own built on pydicom, into Legacy Converted Enhanced CT, MR, and PET instances, leaving every pixel unchanged, so that the multi-frame path is measured on real images; the converted frames are a stratum of their own. Every image IOD that the evaluation measures is gated by the criteria, whether or not it is in the release scope. Regions are also counted by where they lie, in fixed zones at the corners and edges of the frame and at its centre, since curation can leave real text, such as orientation letters or a scale’s numbers, in an image taken to have none, and the zones show whether it did without anyone viewing an image.T4, text burned into real images on the runner. T1’s generator burns text into T3’s images on the runner, at seeded positions, sizes, and contrasts, with exact ink masks, as the core of the evaluation: it measures missed text on real anatomy, for every IOD that T3 covers, with exact ground truth and no one viewing an image. Each image is measured twice, as received for false positives, and with its text for missed text and for false positives away from the text.
T5, text that someone else burned in. Real images into which TCIA burned text, with the coordinates of that text from MIDI-B’s answer key, whose
<pixels_hidden>action the challenge scores as the share of the text’s tokens removed. Their IODs are counted, whatever they are; one outside the release scope still measures text that neither the generator nor this project made, which guards against tuning the detector to T1’s generator. The Pseudo-PHI-DICOM-Data collection (D-018) joins this tier only if its answer key is found to give the coordinates of burned-in text. MIDI-B’s tiers wait for MIDI-B to run on CI’s runners.T6, images read only on a person’s own machine. A development command, run on a person’s own machine on images that they may use, measures them as T3 measures CI’s images, and, where that person has annotated their text, also counts how much of it the detector covers. As the maintainer chose on 31 October 2026, he runs it on his clinic’s RT Images and on the RT Images of a TCIA limited-access collection that holds them, AREN0532 or ARAR0331, for which he applies for access. As he chose on 1 November 2026, the command also burns synthetic text into in-memory copies of those RT Images, by T4’s injection, and counts the pieces of text fully covered, partly covered, and missed, in T4’s fixed bins; nothing is written to disk, and only counts leave the machine. For the limited-access collection, that waits on its licence’s terms being checked against it once he has access. A limited-access collection is never used in CI, since its licence prohibits giving a third party access without the licensor’s written consent (section 4), as a hosted runner would have (D-054). A person may also run it on other exports, such as CT localisers, cone-beam CTs, and dose screens. Like the face block check on DICOM exports (D-054), it renders nothing and prints and writes only counts, and this project’s sessions never run it on real data or read its inputs.
As the maintainer chose on 31 October 2026, before any detection a CI job reads each approved collection on the runner, by the same rules for downloads and redaction, and publishes only an inventory of counts: by SOP Class, Modality, Manufacturer, Rows and Columns in fixed bins, pixel spacing in fixed bins, number of frames in fixed bins, the values of Image Type (0008,0008), such as
LOCALIZER, Burned In Annotation (0028,0301), Photometric Interpretation (0028,0004), and Bits Stored (0028,0101). Manufacturer is mapped to a fixed list of vendors, with any other value counted asother, and every other attribute counted is mapped to its defined terms or standard values, such as the SOP Classes of PS3.4, with any other value, absence, or malformed value counted by a fixed code, so that no free text leaves the runner. The counts show which collections give Enhanced and multi-frame images, localisers, and several vendors, and how to shard or sample a large collection for detection.Every measure is a count in fixed bins, naming no case and giving no value. For each piece of text, the evaluation counts the share of its ink pixels inside a region, and whether all of them are, which is the headline measure of missed text: the text is fully covered or it is not. These are counted by T1’s strata and by IOD, modality, matrix size, and pixel spacing. For each frame without text, and outside the box of every piece of text on a frame with it, the evaluation counts the frames with a region, the regions, the area blacked out as a share of the frame, and the share of that area over tissue, which for CT is the share above -900 HU, as the Text Detector Check counts it, and otherwise the share inside a body mask that the evaluation computes from the frame. These are counted by IOD, modality, matrix size, pixel spacing, and rendering.
The network’s pass is most of the detector’s time, so the runner keeps each rendering’s probability maps of a frame in memory, never written, and gives them a fixed grid of post-processing settings: the pixel and box thresholds, the fill and width limits, and any new shape filter. One pass of the network then gives both measures at every point of the grid, as a trade-off curve. A variant of a rendering or of the network’s input needs a pass of its own.
Each share is given with its Wilson score interval, and, since the slices of a volume and the pieces of text on a frame are correlated, with an interval from a bootstrap over cases, computed on the runner, of which only the interval’s ends leave it. A stratum of fewer cases than a minimum fixed in the code before the first run gives its counts without an interval, since an interval over one or two cases is close to a case’s own value.
The protocol is:
Criteria first. The acceptance criteria below are fixed in this decision before any tuning run. A criterion changed after tuning starts is recorded with its reason, and since the held-out data have then been seen through the tuning they shaped, it needs a fresh held-out set.
Split. Each collection is split by case, by a rule fixed in the code from a digest of each case’s identifier within its collection, so that the split can be reproduced and no list of cases is published: about two thirds for tuning and one third held out. MIDI-B’s test set, Pediatric-CT-SEG, and any collection added after the first tuning run, are held out whole. T1 holds out seeds never used for tuning, and one of its anti-aliased fonts, so that a font never tuned on is confirmed.
Search. Candidates are tried on T1, and on the tuning splits of T2 to T5: renderings, such as a noise estimate over tissue rather than the whole frame, a floor on the window’s width, set in the modality’s output units, such as Hounsfield units for CT, and converted to stored values by the image’s Rescale Slope (0028,1053), since the detector reads stored values and a CT’s are its Hounsfield units only where its slope is 1 and its intercept 0, with the same images stored under other slopes and intercepts tried to show that the floor windows them alike, a structuring element sized in millimetres, and dropping or restricting either top-hat; the network’s input, scaled by millimetres or to a working size, so that frames of 1024 pixels are scaled down; post-processing, by the grid and by shape filters, where a filter on a box’s proportions must be shown on T1 and T4 to keep single letters, whose boxes are nearly square; and the model, among the adoptable models that the next bullet admits, each searched in the same way and reported with its licence and running time, beside the benchmark-only models’ results.
Confirmation. The detector chosen is run once on the held-out data, and those counts are what D-037 records. A criterion that it fails there is reported as failed, that criterion’s IOD is reviewed frame by frame, and the detector is not tuned on the held-out data. A further round of tuning treats those data as tuning data, and is confirmed on data newly held out, such as a collection not yet used. If no candidate passes for any IOD, today’s detector stays the default, every IOD is reviewed frame by frame, and the validation table under Roadmap records that none passed; whether the option is then enabled (D-033) on that evidence and that review is the maintainer’s to decide.
The parts, each with its own pull request, are: this decision; the inventory job; an evaluation library, with T1’s generator, T4’s injection, the measures and the post-processing grid, a counts-only summary of its own format, and variants of the detector, among them an adapter for each vetted model, that a check can select and a run cannot, all tested on synthetic data; a
Text Detector Evaluationworkflow, with the corpora and their shards as a matrix and the variants as inputs, under the Text Detector Check’s rules for downloads and redaction, starting with HaN-Seg and adding MIDI-B and each further collection as it is approved, and publishing the phantoms’ results by case and crops of their regions; the tuning runs, started by the maintainer, and a report of their trade-offs against the criteria; adoption, which makes the chosen detector the default, so changing the method digest (D-024), records its held-out counts in D-037, and updates the validation table under Roadmap; and T6’s command. The Text Detector Check keeps counting false positives on HaN-Seg until the evaluation’s workflow counts what it counts.As the maintainer chose on 31 October 2026, the corpus holds no phantom exports with devices’ burned-in text, since he has not seen a system burn text into RT Images. Real burned-in text comes from T5 and from T6’s runs, and synthetic text, in T1 and T4, covers the rest.
As the maintainer chose on 1 November 2026, the evaluation runs today’s model, PaddleOCR’s PP-OCRv6 small text detection model (D-037), and every other text detection model in two tiers, each through the same harness, measures, split, and criteria, whether or not today’s model meets them. Before a model runs, the licences of its code and its weights are read first-hand, in their authors’ own terms, such as a model card, and its training data are recorded as its authors state them, which a weights’ licence does not govern but a reader may need. Every model runs on the runner, or on the machine of T6’s command, itself: none is a cloud or other OCR service, since the frames of T3 to T6 are real patients’ images.
Adoptable. A model that may become the default: its code and its weights are each under the Apache License 2.0 or a more permissive licence, with none under the GPL and no weights for non-commercial or research use only; it runs in ONNX Runtime; and its weights are pinned by URL and SHA-256, as today’s model is, and CI can download them, or the same weights by the same SHA-256 from another host. Its licences, read first-hand on 1 November 2026 from the projects’ licence files and model cards, admit PaddlePaddle’s own ONNX files of the PP-OCRv6 and PP-OCRv5 text detection models, such as PP-OCRv6 medium and tiny and PP-OCRv5 server and mobile, which RapidOCR 3.10.0’s list of models names by a URL on ModelScope and a SHA-256, under the Apache License 2.0, PaddleOCR’s larger text detection model being checked first; docTR’s text detection models, such as
db_resnet50andfast_base, through OnnxTR, among themFelix92/onnxtr-fast-base, under the Apache License 2.0; and Florence-2, base and large, under the MIT licence, if they convert to ONNX. Beside them is a rule that needs no model, written for the evaluation, which finds connected components of glyph size at the frame’s stored minimum or maximum, where devices often draw their overlays, as a comparator and as a candidate to combine with a model. Each is given to the harness through an adapter of its own in the evaluation library, so that a run of the engine cannot select one before adoption, and is listed here, with the evidence for each licence, once its checks pass.Benchmark only. A model under any licence that allows running it in CI for this evaluation, in any runtime, measured to show the best that any detector achieves, so that the adoptable models are judged against that ceiling as well as against the criteria: EAST, as OpenCV runs it, from a repository under the GPL 3.0; MMOCR’s DBNet++, PSENet, PANet, FCENet, and TextSnake, whose weights’ licences are yet to be read; docTR’s models in PyTorch; Surya, whose code is under the Apache License 2.0 and whose weights are under CC BY-NC-SA 4.0; Tesseract’s layout analysis; and Florence-2. CRAFT’s weights, which EasyOCR’s default detector uses, carry no licence, so all rights in them are reserved and CI, which would copy them, cannot run them; CRAFT and EasyOCR’s default detector are left out until a licence allows it, subject to the maintainer’s correction. Such a model is installed only in the benchmark’s own job, at a pinned version and digest, is never shipped, and is never declared a dependency of PyMedPhys, its extras, or its dependency groups, so it can never become the default.
A model that gives probability maps, as today’s does, takes the post-processing grid; one that does not is measured at each of its own post-processing settings, each a pass of its own.
A crop is published only from a frame that is wholly synthetic or a phantom’s: one of T1’s frames, or a frame of a series on T2’s allow-list, VICTRE’s among them; never from a real patient’s frame, including the synthetic text that T4 burns into one, since a crop would show the anatomy around it, and a region that the detector finds on such a frame may be identifying text that curation missed.
As the maintainer chose on 1 November 2026, the evaluation also publishes results by case for the openly licensed collections of real patients’ images that it takes from NCI’s Imaging Data Commons, and, as he confirmed on the same day, amending for them his choice of 31 October 2026 of counts alone, for the seven openly licensed collections taken from TCIA, as a deliberate exception to the rule above that names no case: in a format of their own,
pymedphys-deid-text-detector-cases/1, keyed by each series’ collection identifier in the Imaging Data Commons, or for a collection taken from TCIA its TCIA collection name, and its Series Instance UID, each series with its collection’s licence and DOI. The exception rests on each collection’s licence, CC BY or CC BY-NC, which allows it, and on those identifiers being public already in the collection’s own listing; it lets a miss or a false positive be traced to its series and reproduced by anyone with the collection. The counts-only summary stays as it is, and the results carry no pixel value and no crop. HaN-Seg stays counts only, since its licence forbids sharing adapted material and D-054 keeps it to counts, and MIDI-B’s sets stay counts only here, since their scoring is the MIDI-B benchmark’s.The acceptance criteria, as the maintainer chose on 1 November 2026, before any tuning run, are as follows; a candidate, which is a model with one setting of its renderings, input, and post-processing, passes for an IOD only if it meets every one there. The gate is per IOD, as the maintainer chose on 1 November 2026 (“Review every frame”). On an IOD for which the adopted detector fails a criterion, or lacks the evidence, Clean Pixel Data stays usable, and its output is held for review and reviewed frame by frame, as D-037 sets out: the QC pack previews every frame at full resolution and a verdict must pass every frame, with or without regions. Review of every frame is the default for every IOD. As the maintainer chose on 1 November 2026 (“Flagged only once the IOD passes”), a review that passes only the frames with regions becomes available for an IOD only once this evaluation’s confirmation shows that the adopted detector meets every criterion for it, with the release report recording the review’s mode and the frames released unseen; that relaxation amends D-037 and D-048 in a decision of its own (D-059), which builds it. It is refused for an IOD that fails a criterion or lacks the evidence, since there the frames without regions are where text may have been missed. The candidate can still be adopted for the IODs that pass. The criteria are:
What counts as found. A piece of text is found only where it is fully covered: every pixel of its ink, those that the generator draws with a coverage above 0.5, lies inside a region. A piece partly covered counts as missed, since one character left readable can identify.
Clearly visible text. In every cell of IOD, contrast, and height in which the contrast is at least 16 times the frame’s robust noise standard deviation and the height at least 7 pixels, at least 0.99 of the pieces of text are found. Contrast is the text’s step from its local background in units of that standard deviation, and height is the text’s cap height in stored pixels.
Faint text. In every cell with a contrast from 4 to under 16 times the noise standard deviation and a height of at least 7 pixels, at least 0.95 are found.
Fainter or smaller text. Text under 4 times the noise standard deviation, or under 7 pixels high, is reported and not required.
Frames altered. Of the frames without text, at most 0.02 give any region for CT, Enhanced CT, cone-beam CT, MR, Enhanced MR, and PET, and for Legacy Converted Enhanced CT, MR, and PET, which take their modality’s cross-sectional limits, and at most 0.05 for RT Image, CR, DX, and XA, whose collimator edges, couch rails, and radiopaque side markers can look like text. As the maintainer chose on 1 November 2026, every image IOD is gated: one that these criteria do not name, such as Secondary Capture, ultrasound, mammography and breast tomosynthesis, nuclear medicine, and radiofluoroscopy, takes the strictest limits, 0.02 of its frames without text and 0.0001 of its tissue, until he assigns it to a group.
Tissue blacked out. Of the tissue pixels of an IOD’s frames without text, pooled, at most 0.0001 are blacked out, for every IOD.
Where those limits apply. Criteria 5 and 6 apply in each IOD and, within it, in each bin of slice size, so that a large frame’s false positives cannot hide among small frames’.
Evidence. Each share is compared at the unfavourable end of its 95% Wilson interval, and must also pass at the unfavourable end of its interval from the bootstrap over cases. A cell with fewer than 400 pieces of text, or 300 frames without text, fails for want of evidence, and its IOD is reviewed frame by frame.
No loss. No stratum of one dimension, such as a font, style, orientation, position, or zone, loses more than 0.02 of its share found against today’s detector at the settings that D-037 describes.
Text that TCIA burned in. No piece of text in MIDI-B’s answer key is missed entirely, by no region overlapping it, and the share fully covered is reported.
Rationale. The detector’s evidence measures one side each: the synthetic phantoms measure missed text only, on drawn backgrounds in one bitmap font, and the Text Detector Check measures false positives only, on two IODs, CT and MR, of one body site, without text; its run on main of 26 October 2026 found a region on 7,162 of the CTs’ 7,581 slices and 719 of the MRs’ 3,613. Neither measures how a change trades missed text against false positives on the same real images, covers PET, RT Image, localisers, or Enhanced and multi-frame images, or tests the fonts and styles that devices burn in. A change tuned on HaN-Seg alone would be fitted to one data set, and could cut its false positives while losing text on images that were never measured. Both sides matter for the option: a missed piece of text is left for review to catch, and a false positive is anatomy that a release blacks out or a reviewer rejects, since a reviewer’s verdict can add regions to the finder’s but not remove them (D-048). Burning text into real images on the runner gives exact ground truth on real anatomy for every IOD in a collection without anyone viewing an image, which is why it is the core; T5 adds text that the generator did not make, and T1 fonts of several families, with one held out, so that the detector is not tuned to its own test. TCIA’s collection pages, read on 31 October 2026, listed RT Image only in two limited-access collections, AREN0532 and ARAR0331, so RT Images of real patients come only from T6: the maintainer’s clinic’s RT Images and one of those collections, read where its licence allows, on his own machine. Burning text into them there measures missed text on real RT Image anatomy, which T4 cannot, since no collection on CI holds RT Image. Fonts are downloaded by digest rather than committed so that the repository and the package carry no font file, and the SIL Open Font License 1.1 allows their use and redistribution with software, though not their sale alone. A piece of text counts as missed unless all of its ink is covered, since a reader can recover text from the part left. Applying each criterion in each cell, at the unfavourable end of an interval and with enough cases, keeps a good cell from hiding a bad one and a small or lucky cell from passing. The limits are judgements, not measurements: that 16 noise standard deviations lie well below devices’ overlays, that side markers do not identify, and that 0.0001 of the tissue is negligible for planning and diagnosis can be revisited with evidence, but only before tuning starts. Fixing the criteria before tuning keeps them from being fitted to the results, and holding out data, confirmed once, keeps the counts that D-037 records from being fitted to the data they describe; splitting by case rather than by slice keeps a volume’s correlated slices on one side, and holding later collections out whole tests sites and scanners that no tuning saw. Phantoms show no patient, so their regions can be seen, which no count can show: what each false positive covers, and so which rendering or filter gave it. The allow-list keeps that exception to phantoms alone, since a series is published only where its collection, Patient ID, UID, and source all say that it is one, and MRI-DIR, whose physical phantom is porcine, which is not used, and whose other subjects are derived from patients, publishes nothing. Counts in fixed bins, rather than statistics such as a median or a maximum, each of which is one case’s value, give no case’s value (D-054), and intervals are withheld for strata of few cases for the same reason. Gating each IOD by review rather than by turning the option off for it keeps an IOD whose detector falls short cleanable, since the option still blacks out what the detector finds, while the review of every frame, which D-037 already requires, catches what it misses; so a shortfall costs review time, not protection. Every adoptable model is measured against the same criteria, rather than only when today’s fails them, so that the model chosen is the best that meets them, not the first, and the adoptable tier holds each to the licence and runtime rules that today’s model meets, so that adopting one changes no dependency’s terms. The benchmark-only tier measures how far the best adoptable model falls short of the best detector that can be run at all, which the licence rule alone would hide, without letting any such model reach the package; no model runs as a service, since sending real patients’ frames to one would take them off the runner. Keeping the probability maps in memory makes post-processing nearly free to vary, since the detector takes seconds a slice; MIDI-B’s 53,581 instances need sharding across matrix jobs to fit the six hours that a hosted runner allows. HaN-Seg’s licence, CC BY-NC-ND 4.0, forbids sharing adapted material, not making it, and the images with text burned in never leave the runner; the CC BY licences allow both, and NSCLC-Radiomics’ CC BY-NC 3.0, like HaN-Seg’s, allows non-commercial use, which testing open-source software is, as D-054 has it for HaN-Seg. The same holds for
midrc_ricord_1candbreast_cancer_screening_dbtunder CC BY-NC 4.0, whose non-commercial use, one not primarily intended for or directed towards commercial advantage or monetary compensation, includes a public benchmark of open-source software in CI; the counts that it publishes share none of the licensed material.Tests. Each part ships its own. Among them: the generator gives the same frames and masks for the same seed and different ones for another, covers every stratum, and draws each piece of text’s ink exactly where its mask lies; injection changes only the pixels of its masks and leaves every other value as received; on hand-made cases, a region over all of a text’s ink counts it fully covered, one that leaves a pixel uncovered does not, and a region outside every text’s box counts as a false positive; the grid’s result at the detector’s own parameters, from the kept probability maps, equals the detector’s regions; the split gives the same cases each time, near its fractions, holds out Pediatric-CT-SEG whole, and names none; each criterion fails a candidate that misses it by one piece of text or one frame, and a cell short of its minimum fails; a stratum below the minimum gives no interval; a run cannot select a variant of the detector; a benchmark-only model is installed only in its job and is no dependency of the package, its extras, or its groups; each adoptable model’s adapter refuses weights without their pinned SHA-256 and gives the harness regions in the form that the measures take, with probability maps for the grid where the model makes them; the summary holds only integers, bin edges, intervals, settings, and the detector’s method, and is the same each time; the workflow downloads only on a hosted runner and reports a crash without a message or path; the inventory maps a manufacturer off its list, an Image Type value that is not a defined term, and a malformed or absent value to their fixed codes, and holds no free text; the results by case name only series of an openly licensed collection from the Imaging Data Commons or of the seven taken from TCIA, by its collection identifier or name and Series Instance UID, and never one of HaN-Seg or MIDI-B, with its licence and DOI, and hold no pixel value; a single-frame series converted to Legacy Converted Enhanced instances keeps every pixel and is counted in a stratum of its own; an IOD that the criteria do not name takes the strictest limits; a series whose licence is not on the list is refused; a crop is published only for a series on the phantom allow-list that the workflow downloaded from its collection, and a case’s result only for such a series or a series of an openly licensed collection from the Imaging Data Commons or of the seven taken from TCIA, and any other series, among them every series of MRI-DIR’s computational subjects, HaN-Seg’s, and MIDI-B’s, is only counted; an IOD that fails a criterion or lacks the evidence keeps Clean Pixel Data usable and refuses any review that would pass only its frames with regions; T6’s command reads files only where they lie, burns text only into copies in memory, leaving every file as it was, renders nothing, writes only counts, and reports a crash without a message or path; and adoption’s detector is in the method digest that the markers and the release report record.
D-057: Checking the face block and CT defacing on the NLM Visible Human Project’s CT#
Decision.
As the maintainer chose on 1 November 2026, the CT of the two cadavers of the U.S. National Library of Medicine’s Visible Human Project is public, held-out evidence for the face block finder (D-046) and CT defacing (D-050), checked in CI, and both cadavers’ faces are rendered in its results. The cadavers are the one exception that the maintainer made to the project’s rule that no real person’s images are processed except as counts. Their source is NCI Imaging Data Commons’ DICOM conversion, the collection
nlm_visible_human_projectat IDC data release v19 (doi:10.5281/zenodo.16114440), in IDC’s public bucketidc-open-data, which each series gives under “National Library of Medicine Terms and Conditions; May 21, 2019”. Those terms ask each user to acknowledge NLM with the phrase “Courtesy of the U.S. National Library of Medicine” in a clear and conspicuous manner and not to imply NLM’s endorsement, and each redistributor to keep the most current version or to say clearly that what it distributes may not be current. The check’s summary, its page, the workflow, and each render carry the phrase and a notice that says the other two. No part of a series is committed, cached, or uploaded; the results and the renders are the workflow’s artefact.The check,
pymedphys._dicom.deidentify.face_validation_vhp, run aspython -m pymedphys._dicom.deidentify.face_validation_command visible-human, pins each of the collection’s 11 CT series by IDC’scrdc_series_uuid, its file count, and the SHA-256 of the lines of its files’ SHA-256 digests and names in the order of the names’ bytes, and refuses a set in which any series differs before it checks any. Only a GitHub-hosted runner of theFace Block Check on Visible Humanworkflow (.github/workflows/face-validation-visible-human.yml), started by hand, downloads them, anonymously over HTTPS with.github/scripts/fetch_idc_series.py, which uses the standard library alone.IDC keeps each scan as one series whose field of view, and so pixel spacing, changes along the body, so the check gives each series’ slices to the finder three ways: every file to
find_face_blocksas a run’s records, as a run gives them; each stack of slices that share orientation, pixel spacing, rows and columns, and in-plane origin tofind_face_blocksas a series of its own; and the slices within the 400 mm head reach of the series’ superior end, each resampled by linear interpolation onto the in-plane grid of the stack with the largest field of view, toFaceFinderdirectly, which a run does not do and so bears on the finder’s anatomy tests alone. Of each way, it reports the outcome, whatFaceFinder.inspectsaw (the voxel, the balls considered, tested, and kept, and the pairs tested, in the orbits, and passing), and the globes and block found.No mask marks the globes, so the reference for each of the three series that hold a head (the female’s, and the male’s before and after freezing) is a centre placed by hand for each globe on the native slices, from axial, coronal, and sagittal views and profiles of Hounsfield units, as the midpoint of the globe’s extent along each axis, within 3 mm, before any measure against it was taken. Against them, the check reports each found globe’s distance from the reference on its side, whether the sides are swapped, the ball that the finder considered nearest each reference with its radius and surround test’s shares, and the tests of the pair of kept balls nearest them; and, about each reference, the median Hounsfield units, and the share in the finder’s soft tissue window, of the pixels within 6 mm of its centre and of those from 13.2 mm to 18 mm, where a living globe’s orbital fat lies.
Each block found, and a reference block placed from the reference globes as the finder places one from globes of 12 mm radius (its plane 5 mm behind their midpoint, perpendicular to the line between them, and its floor at their lower inferior edge, lowered by the finder’s least voxel or the slices’ greatest gap there), so that defacing is exercised on real anatomy even where the finder refuses, is given with each slice of the series to
CtDefacer, as a run gives it. The check reports the slices and volume written as air, the tissue among it (above -500 Hounsfield units), the tissue in the block that is kept, as the brain is, any pixel written outside the block, and each reference globe’s share of a 12 mm sphere written as air and whether its anterior pole is; and, for a found block, its plane’s distance ahead of the reference block’s at the reference midpoint, the angle between them, and its floor’s height above the reference floor.For each of the three heads, the stack that holds its globes is rendered as the QC pack renders a CT series’ skin surface, as received and as each block would deface it, with axial, coronal, and sagittal slices through each reference globe, the reference and found globes and each block’s edges marked.
The scans are held-out evidence: the finder’s settings were not set from them, and none is to be changed from what they show. A change that they prompt needs evidence from other data and a decision of its own, as does treating a series of several stacks otherwise than as
not-one-stack.
Rationale. No phantom found has real globes, orbital fat, a bony orbit, a closed skull, and a face together, and HaN-Seg, which has the anatomy, tuned the finder (D-050, D-054) and is a set of patients whose faces may not be shown. The Visible Human’s CT has all five, may be redistributed under NLM’s terms, which place no limit on modification, commercial use, or use in CI, and is served without an account, so a public runner can download it and anyone can reproduce the results. The donors were not patients, but each was a real person, so the maintainer allowed these two cadavers alone, and, on 1 November 2026, renders of both their faces, although the male donor is publicly named. A run’s own outcome is reported first, because it is what a release would do; the stacks show what a run would do with each field of view as its own series, and resampling separates the finder’s anatomy tests from its stack checks, at the cost of interpolation that a run never applies. Reference centres placed by hand are a weaker reference than HaN-Seg’s curated masks, so their tolerance is stated and the slices through each globe are rendered, so that a reader can judge them. The scans are post-mortem, from an early 1990s scanner, and one male scan was made frozen, when water reads as ice, below the finder’s soft tissue window, so they bear on the finder’s tests of real anatomy, not on its yield on clinical CT, which the HaN-Seg check and the check of planning exports (D-054) measure.
Tests. On the analytic head written as IDC keeps a Visible Human scan, one series of a head stack at 1 mm pixels above a body stack at 2 mm, the check finds a run’s outcome
not-one-stack, the head’s stack giving a block within 2 mm of the reference globes with its pair passing every test and each ball at a reference kept, and the resampled slices a block on the body stack’s grid; each block, and the reference block, written byCtDefacerwith no pixel outside the block, more than half of each reference globe, and its anterior pole; the reference block placed 5 mm behind the globes and lowered by the slices’ 2.5 mm gap; the tissue about each reference globe measured as vitreous; a rendered series’ renders written as PNG files with a notice carrying the attribution, and no render for a series not rendered; the summary carrying the source, terms, attribution, and notice; a missing or changed series refused before anything is rendered; the manifest digest that ofsha256sumsorted by name; the page as CommonMark with the attribution at its head and foot; and the command writing the summary, the page, and the renders, printing the page, and refusing an existing output directory or a missing series.
D-058: Checking and rendering the face block and CT defacing on Steven Keating’s cranial CT#
Decision.
Steven Keating’s cranial CT, which he released on Zenodo in 2014 as “Open access (CC0) with approval from patient” (doi:10.5281/zenodo.16816), is public, held-out evidence for the face block finder (D-046) and CT defacing (D-050), checked in CI, and its face is rendered in the results, in place of the painted globes of a phantom. It is one ZIP file of a hospital’s CD export: one acquisition of the head, from below the chin to the vertex, reconstructed as two axial CT series of 216 slices 1.25 mm apart, on 284 mm and 500 mm fields of view, with two localisers, a screen capture, a structured report, and the CD’s viewer. Its headers carry the identifiers of its subject, who published them; the check’s summary and page hold none of them, and no part of the file is committed, cached, or uploaded: the results and the renders are the workflow’s artefact.
The check,
pymedphys._dicom.deidentify.face_validation_keating, run aspython -m pymedphys._dicom.deidentify.face_validation_command keating, pins the file by the size and MD5 that the record gives and its SHA-256, writes the files of each axial series, those of the CT Image Storage SOP Class whose Image Type’s third value isAXIAL, into a folder of its own in a temporary directory, pins each series by its file count and the digest that D-057 uses, and refuses the file, or a series, that differs, before it checks either. Only a GitHub-hosted runner of theFace Block Check on Keatingworkflow (.github/workflows/face-validation-keating.yml), started by hand, downloads it, from Zenodo, and checks its size and MD5 against the record’s.Each series is checked as D-057 checks a Visible Human series, by the same code: given to the finder as a run gives it, by stack, and resampled; measured against a reference centre for each globe, placed by hand before the finder was run on the scan, from axial and sagittal views and profiles of Hounsfield units along each axis, as the midpoint of the globe’s extent between the peaks of the sclera and from the cornea’s front against air, within 3 mm, the same in both series; with the Hounsfield units about each reference; with each block found, and the reference block, given with each slice to
CtDefacer, and what it would write measured; and with each series’ skin surface rendered as received and as each block would deface it, and slices through each reference globe with the globes and blocks marked. Each render carries a credit for the record and the held-out statement, and the notice beside them says that no endorsement by him is implied.The scan is held-out evidence: the finder’s settings were not set from it, and none is to be changed from what it shows. A change that it prompts needs evidence from other data and a decision of its own.
Rationale. The painted globes of a phantom show the finder and the renders only what was painted, and the Visible Human’s cadavers (D-057) are post-mortem, imaged by an early 1990s scanner. This scan is a living adult’s head, imaged by a clinical scanner with clinical reconstruction, with globes, lenses, orbital fat, bony orbits, and a face in front of air, so it is the closest public match to what a run defaces. CC0 places no limit on use, modification, or redistribution, and its subject approved its open release and has campaigned for patients’ access to their own data, so rendering his face in public results is within both the licence and his stated approval; it is the only living person’s head CT found whose subject chose to make it public. Its craniotomy, three months after an astrocytoma was resected, exercises the finder’s cranium test and the brain that defacing keeps, which bone at 300 Hounsfield units or more must enclose within a slice, on a skull that is not intact. Two reconstructions of one acquisition show how the finder’s outcome depends on the field of view and pixel spacing alone. A reference placed by hand is weaker than curated masks, so its method and tolerance are stated and the slices through each globe are rendered for a reader to judge. One subject and one scanner bear on the finder’s tests of real anatomy, not on its yield on clinical CT, which the HaN-Seg and PDDCA checks and the check of planning exports (D-054) measure.
Tests. On the analytic head written as a CD export laid out as the record’s, with a localiser, a structured report, a viewer, and the macOS archiver’s metadata among the series’ files, and names repeated across folders, the check extracts only each series’ axial CT Image files, named for their folders; finds a block in each series within 2 mm of the reference globes, its sides not swapped, with no pixel written outside the block and each reference globe’s anterior pole written; writes a rendered series’ renders as PNG files with a notice that carries the record’s credit and not NLM’s, and none for a series not rendered; carries the record, licence, and held-out statement in the summary, and no value of the headers; refuses a changed file, and a series whose files differ, before anything is rendered; gives the page as CommonMark with the credit at its head and foot and no blank lines in a row; and its command writes the summary, the page, and the renders, prints the page, and refuses an existing output directory or a file that is not the one pinned, without quoting its path.
D-059: Reviewing redactions in a local app#
Decision.
A private command,
python -m pymedphys._dicom.deidentify.redaction_review_app PACK, serves the reviewer a page in their own browser for giving the redaction verdicts of a QC pack that has not been attested (D-048), as the maintainer asked on 1 November 2026 for “a very nice, snappy, user-friendly UI for users to block out the text themselves when candidates are flagged, and also the option to just review all images”. Like the tool’s other commands, it is kept out of thepymedphyscommand line until the first supported release.The page shows each cleaned instance’s frames one at a time, with the finder’s regions outlined as proposals over the frame as received. The reviewer keeps or drops each proposal with a click, draws a region over text that the finder missed by dragging over it, and resizes or deletes a region that they drew; a region that a reviewed region rule gave is shown and cannot be dropped (D-037). A region belongs to the frame on which the reviewer began drawing or resizing it: until the pointer is released, the page ignores its keys other than Escape, which cancels the region, cancels the region if the frame or instance changes another way, and refuses a verdict. The page shows the frame as the run given the verdict would write it, with every kept and drawn region blacked out; it windows the frame by percentiles, over its full range, or inverted, and by dragging, and zooms and pans; and it works from the keyboard. Its summary magnifies every region dropped or drawn, each in a window of its own, beside the command that records the attestation. Confirming gives the instance an accepted verdict where the reviewer changed nothing, and a revised one otherwise; rejecting is possible at any time; and any change to the regions clears a verdict.
Each frame of a cleaned instance has a review frame in the QC pack, after its preview, from which the page draws its views: for a monochrome frame, a 16-bit grey PNG mapped linearly from the frame’s full range to 1 to 65,535, brightest last, with MONOCHROME1 inverted and pixel padding 0, and for a colour frame, its 8-bit RGB. It shows the frame as received where the frame has regions, and as written where it has none, as the previews do (D-037). The pack records each review frame’s SHA-256 with the other previews’, and the server checks it before it sends the frame, so the page shows only what the attestation binds.
The page records a frame as shown once the whole frame has been on screen, with the page visible and none of its dialogs open, for 300 ms without a break, so hiding the page or opening a dialog starts the count again; this records that the frame was displayed, not that it was examined. An accepted or revised verdict holds the frames that the reviewer was shown, and attesting refuses one that was not shown every frame that its review requires. The review of an instance requires every frame, unless its SOP Class UID, which the pack records, is one of
FLAGGED_ONLY_SOP_CLASSES, whose review requires only the frames with regions; attesting records which of these two modes,every-frameorflagged-frames, each accepted or revised verdict was reviewed in, and refuses a verdict given with a mode of its own. As the maintainer chose on 1 November 2026, the set is empty, so every frame of every IOD is reviewed, and an IOD joins it only once the text detector’s evaluation on real DICOM files of that IOD shows that it meets the maintainer’s acceptance criteria, by a change to the set that is itself reviewed. The release report counts the accepted and revised source files reviewed in each mode, a file whose copies were reviewed in both counting asflagged-frames, and the frames of those files that the reviewer was not shown, so a release that relied on flagged-only review says so, even where the reviewer happened to be shown every frame (D-048).The page saves the reviewer’s work as it goes, in
redaction-verdicts.jsonbeside the pack, labelledpymedphys-deid-redaction-verdicts/1and bound to the pack’s reference and SHA-256, written to a temporary file and moved into place, mode 0600 on POSIX, so a review can stop and resume. The page sends each instance’s changes one request at a time, so an earlier change cannot be saved over a later one; it reports the work saved only once the server has confirmed saving the latest change to every instance, keeps reporting a failed save until a retry succeeds, asks before the page is left with work unsaved, and its summary says whether the app can be stopped yet. An instance’s entry without a verdict is work in progress. The attestation command’s--redaction-verdictsreads the file, refuses one saved for another pack or for this pack before it changed, and records the entries with a verdict; it replaces the options that typed a verdict and its regions.The pages show patient pixel data, so the server is local and closed. It listens on 127.0.0.1 alone, on a port that the operating system chooses unless one is given; it answers only a request whose Host is that address or
localhostat that port; every request for data or to save must carry a random token, which the printed address holds after its#, in a request header; it serves only the page, its script and style from the package, the session’s description of the pack, and the review frames; it accepts only GET and PUT, and a PUT of JSON within a size limit; and its responses forbid caching, framing, and sniffing, with a Content Security Policy that lets the page reach this server alone. The page loads no third-party code, font, or service. Neither the server nor its messages name the pack’s path, a source path, or any value, and no message, page, or file that it writes cites a decision of this design.
Rationale. Typing coordinates read from a preview is slow and invites the errors that attesting cannot detect, a region transposed or given for another frame (D-048), whereas a region drawn on the frame cannot have either. Treating the finder’s regions as proposals lets a reviewer clear its false positives over anatomy, which otherwise blacks out image content that a recipient may need, while a rule’s regions stay, since a reviewer has already found text there (D-037). The maintainer chose to require every frame until the detector is shown to meet his criteria for an IOD because flagged-only review releases a frame in which the finder found nothing without anyone having seen it, and on synthetic phantoms the detector found only 55 to 82% of faint strings (D-037); recording each approval’s mode, and counting the files reviewed in each and the frames not shown in the release report, keeps that choice visible once an IOD is unlocked, as D-056 requires; the count of frames not shown alone could not tell a review of every frame from a flagged-only review that happened to show them all. Attesting, not the reviewer or the app, records the mode, from the engine’s set at the time, so a mode cannot be claimed that the review did not enforce. The review frames keep the frame’s full depth so that the reviewer can window faint text near the extremes, which an 8-bit preview in one window can hide (D-037), and checking their digests before serving them keeps the review to the bytes that the attestation binds. A page in the reviewer’s browser, served by the standard library, adds no dependency and no build for any platform, whereas a desktop toolkit would add both; a hosted service was rejected because the frames show patient data. A loopback port can be reached by any local process and by any web page in the reviewer’s browser, so the token, which the browser never sends to a server in the address and which another site’s page cannot send in a header without a preflight that the server never grants, keeps others out, and the Host check stops a page that rebinds a name of its own to this computer. The attestation reads the saved file, not the page, so the page reports work saved only once the server has confirmed it. Recording that a frame was displayed is all that a page can know, and a frame in a hidden page or under a dialog is not displayed; whether the reviewer examined it rests on the attestation, as it does for the other previews (D-017).
Tests. Review frames: linear over the full range, brightest last, MONOCHROME1 inverted, padding 0, colour as 8-bit RGB, one after each preview of a cleaned frame, recorded with its SHA-256, and read back by the PNG reader, which refuses a PNG of another kind or with a bad checksum. Required frames: every frame by default, only the flagged frames for a SOP Class in the set, and every frame for any other SOP Class; attesting records each approval’s mode, refuses a verdict given with one, and a mode on a rejected verdict, and reading refuses an attested approval without one; a review counts approved files by mode, copies reviewed in both as
flagged-frames, and the release report records the counts and refuses them missing, incomplete, negative, or without a reference; attesting refuses an accepted or revised verdict not shown a required frame, but not a rejected one. The verdicts file: written and read back, refused when malformed, of another format, or for another pack or a changed pack, written atomically with mode 0600. The server: the session describes each cleaned instance, its regions, rules, and required frames, and no path or value; frames are served as raw samples after their digests are checked, and refused where a preview changed; requests without the token, with a wrong one, or with another Host are refused; responses carry the security headers; drafts are checked and saved, and refused when malformed, too large, or not JSON; other methods are refused; the static files load nothing from elsewhere and cite no decision; and the command refuses a directory without a pack, or with an attested one, and starts and stops cleanly. The page: its script, driven in Node.js against a stand-in for the browser and a server whose answers the test controls, keeps a region on the frame and instance where it was begun when the reviewer tries to change frame or instance while drawing or resizing it, and refuses a verdict meanwhile; reports work saved only once the server has confirmed the latest change to every instance, not when an older save completes, while a newer one waits or is in flight, or while another instance’s save has failed; and counts a frame as shown only after 300 ms with the page visible and no dialog open.
Roadmap#
Milestones group outcomes; they are not a sequence of pull requests or releases. Each pull request ships its own tests, documentation, and traceability, and M6 consolidates the evidence. The first supported release needs only the parts of M1 to M5 that its scope uses.
Milestone |
Outcomes |
Done when |
|---|---|---|
M0 Legacy hygiene |
Diagnostics free of identifying values and paths; limitation warnings and notices (D-019); pydicom minimum (D-002) |
Each change has regression tests and documentation, and remaining disclosure channels are listed in the tracking issue. Hygiene does not make the legacy tools conform. |
M1 Standard |
Table generator and generated tables, including the PS3.3 Types of every composite IOD with its Functional Group Macros, generated for all but the three real-time IODs, which also need PS3.6 Table 9-1 (D-001); requirements register; monthly edition check (D-001) |
Source provenance and table coverage are verified, and the generator and generated data are reviewed separately. |
M2 Primitives |
Keys and subject profiles; UID replacement; patient pseudonyms; date offsets; VR and VM validators and dummy values (D-021); rule layers, including the reviewed rules for the text, dates, times, and other attributes that Table E.1-1 omits (D-022, D-023), and preset composition; method digest (D-024) |
Primitives and policy conflicts are validated before integration. Hypothesis is added with the first property tests that use it. |
M3 Engine |
Dataset transformation, with actions resolved by Type (D-020) and markers (D-012); file container (D-025); private attributes (D-028); descriptor cleaning; bitstream metadata; dataset-level API |
Each component has tests, API documentation, and conformance evidence for explicitly supported input. A dataset-level API does not establish collection integrity or readiness to release. |
M4 Pipeline |
Discovery and writing through a staging area; reference graph with graded consequences (D-026) and two-pass verification; residual search (D-027); reports; risk detection; QC pack and attestation; statistical assessment; end-to-end preset validation |
Graph and subject consistency, the separation of reports, QC material, and state, and every preset gate are verified. |
M5 Interfaces and migration |
Command line using the same engine as the library, for the first supported release, including the nomenclature converter commands that run as |
Only supported behaviour is exposed, with user documentation. |
M6 First supported release |
Every preset and every option enabled, each once validated, the release waiting until all are (Scope); how-to guide, generated conformance statement, requirements-to-tests matrix, and benchmark results (D-018) for the release scope |
Evidence is published for the shipped coverage and exclusions are documented; the evidence is refreshed for each later release. |
M7 Legacy removal |
Removal of both legacy interfaces |
The deprecation window in D-019 has passed. |
On 10 October 2026 the maintainer postponed the first supported release until the tool is more comprehensive and its public validation much more comprehensive, as public and reproducible as possible, and decided that the release pull request opens only once its release criteria hold, rather than taking them as blockers inside it. The criteria are:
every internal error that the MIDI-B benchmark runs report is fixed;
the MIDI-B score is high, with its target set once the benchmark’s triage shows what is achievable;
every answer-key failure on a released instance is fixed, or recorded, with MIDI-B evidence, as a deliberate difference (D-018);
the MIDI-B yield and each category of unreleased instance are published in the documentation, with the code that reproduces them;
the independent validators run in continuous integration and fail on any finding outside the reviewed known differences (D-030);
the fuzz testing of the engine’s parsers of untrusted bytes has merged;
the maintainer’s pilot on a representative local export, under each preset, is summarised by reason counts; and
every preset and every option is validated for the release scope, as defined below and as D-033 requires before each is enabled.
The pilot stays a criterion because the MIDI-B collection holds no RT Structure Set, RT Plan, or RT Dose, and a curated benchmark, whose clinical images carry injected synthetic identifiers, cannot show how often a department’s own exports meet the conditions that withhold a whole subject (D-027) or stop a run (D-026).
On 25 October 2026 the maintainer decided that the first supported release ships every preset and every option (Scope), and that it waits until every one is validated, rather than shipping basic and basic-clean-descriptors first; the last criterion records this. The MIDI-B criteria bear on the policies that the benchmark runs select, so an option’s validation is its own: for example, Clean Recognizable Visual Features needs the face checks (D-050, D-054), and an option that the MIDI-B data do not exercise needs other evidence.
On 25 October 2026 the maintainer also adopted what validated means. A preset or option is validated for the release scope when it has evidence at each of three levels:
Synthetic, in continuous integration. Its run over the synthetic corpus passes end to end and through the independent validators (D-030), and its conformance statement lists nothing under “Not yet described” (D-033).
Public and reproducible, on real images. A MIDI-B run under it, scored per answer-key category (D-018), with a flip check for each Retain option: between a run under
basicand one underbasicwith the option, only checks of attributes on the option’s rows of Table E.1-1 change outcome, and, where MIDI-B exercises the option, those that change show its intended effect. A check on those rows may keep its outcome, as a check that a date was shifted does, since it passes whether the Basic Profile removes the date or Modified Dates shifts it. Where MIDI-B does not exercise an option, the option’s own public check stands in, as the face block check on HaN-Seg does for Clean Recognizable Visual Features (D-054).Local. The maintainer’s pilot on a representative local export under each preset, summarised by reason counts. The development command
python -m pymedphys._dicom.deidentify.pilot_commandruns it: it takes any preset or custom option set, enabled or not, runs it through the whole pipeline under a new run-scoped key, and prints only counts, and what it releases is for validation only. An option is piloted through each preset that selects it, and an option that no preset selects is piloted under one custom option set of every such option, as the maintainer decided on 26 October 2026, over a pilot of each such option alone or none.
The table gives each preset’s and option’s evidence at each level, as it stands on main on 26 October 2026. “Met” means the evidence is in place, and every other cell says what is missing. A pull request that adds evidence updates the cells it meets, and the release pull request opens only once every cell is met. The first level is met for every row: tests/dicom/corpus_runs/ holds a run of each preset, a run of each option alone, and runs of basic over compressed input, of Clean Pixel Data with a reviewed QC pack, and of nine options together, and the independent validators check each run’s output.
Preset or option |
Synthetic, in CI |
Public and reproducible |
Local |
|---|---|---|---|
|
Met |
Not yet: the MIDI-B criteria above |
Not yet |
|
Met |
Not yet: the MIDI-B criteria above |
Not yet |
|
Met, with no conformance claim, by design (D-007) |
Not yet: a MIDI-B run under it |
Not yet |
|
Met |
Not yet: a MIDI-B run under it |
Not yet |
Retain Safe Private |
Met |
Not yet: a MIDI-B run under it with each safe private list (D-035), and its flip check |
Not yet: through |
Retain UIDs |
Met |
Not yet: a MIDI-B run under it, and its flip check |
Not yet: under the option set of options that no preset selects |
Retain Device Identity |
Met |
Not yet: a MIDI-B run under it, and its flip check |
Not yet: through |
Retain Institution Identity |
Met |
Not yet: a MIDI-B run under it, and its flip check |
Not yet: under the option set of options that no preset selects |
Retain Patient Characteristics |
Met |
Not yet: a MIDI-B run under it, and its flip check |
Not yet: through |
Retain Longitudinal Temporal Information with Full Dates |
Met |
Not yet: a MIDI-B run under it, and its flip check |
Not yet: under the option set of options that no preset selects |
Retain Longitudinal Temporal Information with Modified Dates |
Met |
Not yet: a MIDI-B run under it, and its flip check |
Not yet: through |
Clean Descriptors |
Met |
Not yet: the MIDI-B run under |
Not yet: through |
Clean Structured Content |
Met |
Not yet: a MIDI-B run under it, over MIDI-B’s Comprehensive SR and Enhanced SR instances once Structured Reports are in the release scope |
Not yet: through |
Clean Graphics |
Met |
Not yet: a MIDI-B run under it, which also shows how many of MIDI-B’s instances carry overlays or graphic annotations |
Not yet: under the option set of options that no preset selects |
Clean Pixel Data |
Met |
Not yet: the text detector’s evaluation, with a detector that meets its acceptance criteria on the held-out data (D-056), and a MIDI-B run under it |
Not yet: under the option set of options that no preset selects |
Clean Recognizable Visual Features |
Met |
Not yet: the face block check on HaN-Seg (D-054), and on the Visible Human’s CT (D-057) |
Not yet: through |
Later work needs its own design, tests, and conformance review: accompanying spreadsheets pseudonymised with the same key, the Encrypted Attributes Sequence for controlled sharing (D-013), and the unsupported objects listed under Scope. Generating a table in M1 does not enable the corresponding option or support the corresponding IOD.