Skip to content

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.

Saphira Linux dragon mascot

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

Knobs
VariableDefaultMeaning
LB_SAPHIRA_STATE_CHANGING0Must be 1: the guard gate
LB_SAPHIRA_DICOM_AET / AECSAPHIRA-HC / ANY-SCPAssociation identities
(target port)$4, else 104The SCP's storage port

Wiring it up

ldirectord
# 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

Manual run
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.

Ask about professional support →