Architecture
dicomqc separates file discovery, DICOM parsing, policy evaluation, and report generation. The separation keeps the audit read-only and prevents report formats from becoming coupled to pydicom objects.
Current v0.1 data flow. Raw tag values remain internal to the audit process; report writers emit findings, value states, and aggregate evidence.
Component boundaries
| Component | Current responsibility |
|---|---|
| CLI and scanner | Expand input paths, discover files recursively, select a profile, and coordinate outputs. |
DicomBackend | Read one file and return a normalized MetadataRecord. |
PydicomBackend | Parse DICOM metadata with stop_before_pixels=True; pixel data is not loaded. |
| Metadata model | Represent file context, normalized tags, private-tag status, and ValueState. |
| Built-in rules | Evaluate direct PHI fields, pseudonym patterns, and private tags under research-release-v0.1. |
| Result model | Collect records, findings, skipped files, counts, and the process exit status. |
| Report writers | Produce JSON, CSV, and MultiQC-compatible artifacts without serializing raw tag values. |
Data flow
scan_paths()expands files and directories into a deterministic audit set.- The backend reads each file as DICOM metadata. Files that cannot be parsed are recorded as skipped rather than silently ignored.
- pydicom elements are normalized into
DicomTagobjects inside aMetadataRecord. - Built-in rules may inspect internal values and produce structured
Findingobjects with severity, tag context, and remediation guidance. ScanResultcombines records, findings, and skipped-file reasons. Its exit code is0for pass,1for review warnings, and2for errors or skipped files.- Report writers convert that result into review artifacts. Raw DICOM values are deliberately excluded from report serialization.
Backend boundary
The parser is isolated behind a small protocol:
class DicomBackend(Protocol):
def read_metadata(self, path: Path) -> MetadataRecord:
...
The scanner and rule modules operate on normalized records and do not depend on pydicom dataset objects. This makes parser behavior testable and leaves room for alternative metadata readers without changing policy logic.
Metadata and reporting boundary
MetadataRecord includes file-level context such as modality, manufacturer,
Study Instance UID, and Series Instance UID, together with normalized tag
records. Each DicomTag tracks its number, keyword, value representation,
private-tag status, value state, and an internal raw value.
The raw value is available to rules because pattern checks require it. It is not written to JSON, CSV, or MultiQC outputs. This is a reporting boundary, not a claim that every remaining metadata field is non-identifying; release artifacts still require appropriate governance and access control.
Extension direction
The current package ships one built-in profile. Planned plugin discovery, policy-language support, vendor fingerprinting, and standards-specific rule packs should extend the rule and backend boundaries rather than bypass them. See Extending dicomqc for the proposed interfaces and the distinction between current and planned capabilities.