RTFM · Medical healthchecks
lb.saphira.dicom.store: store a synthetic image (C-STORE, opt-in)
The write-path proof: the check generates a tiny valid DICOM image at check time, 2×2 pixels, purely synthetic, and stores it through the normal C-STORE path. The archive's intake pipeline either works or the check says no.
What it proves
The full storage transaction: association negotiation, presentation-ctx agreement, the C-STORE of a real (if minuscule) DICOM Part-10 object, and the SCP's storage acknowledgement. Writing is the archive's core promise: this is the check that certifies it.
Safety class: DEEP / opt-in; storage mutates PACS state. The check hard-refuses (exit 2) unless LB_SAPHIRA_STATE_CHANGING=1. Never enable as a high-frequency default.
How it works
The packaged generator (lb-saphira-dicom-synth.py) emits a minimal valid Secondary Capture object: 2×2 pixel, Implicit VR Little Endian, PatientName SAPHIRA^SYNTHETIC^HEALTHCHECK, synthetic UIDs; into a temporary file that is removed on exit. storescu (DCMTK) then pushes it exactly as a modality would. No upstream sample files exist anywhere in the package: nothing resembling real patient data can ever be shipped or stored by accident.
Configuration
| Variable | Default | Meaning |
|---|---|---|
| LB_SAPHIRA_STATE_CHANGING | 0 | Must be 1: the guard gate |
| LB_SAPHIRA_DICOM_AET / AEC | SAPHIRA-HC / ANY-SCP | Association identities |
| (target port) | $4, else 104 | The SCP's storage port |
Wiring it up
# ldirectord.cf - opt-in
virtual = 21
protocol = fwm
scheduler = rr
real = 192.168.20.21:104 gate 1
checktype = external
checkcommand = "/var/lib/lb/saphira/lb.saphira.dicom.store"
checkinterval = 300
Run it by hand
LB_SAPHIRA_STATE_CHANGING=1 \
/var/lib/lb/saphira/lb.saphira.dicom.store pacs-pool 104 192.168.20.21 104
echo $?
# 0 = synthetic object stored and acknowledged
# 1 = storage refused or failed
# 2 = guard not set - the check refuses to run
Failure modes
- Storage refused: the archive's intake AE title/whitelist changed; the check caught it before a real scanner did
- Generator failure: a broken python3 or package layout: exit 1, investigate the director
Did we miss something?
If this page left something unanswered, found an error, or there is another subject you would like documented, tell us. Saphira’s documentation grows from real problems people need to solve.
Send feedback or request a new section →
Prefer not to do it yourself?
Everything needed to do the work yourself is documented here and remains free; we charge for human time, not for withholding knowledge. Sometimes the missing resource is simply time. The same people who build Saphira can provide paid professional help with implementation, migration, troubleshooting and administration.