Worklist procedure capture and review history: Requested/Performed Procedure validation, server-owned Meta keys, and per-transition history
Server-side implementation of the worklist enhancements specified in #54 (closed): structured Requested Procedure / Performed Procedure capture and a per-transition review history, stored entirely in the work item's existing orthanc JSONB (no schema change). Client counterpart: oak-tree/medical-imaging/ohif-viewers!58. Functional test coverage: sonador-ftests!10 (merged).
What's included
sonador_orthanc/validation/procedure.py (new) — ProcedureValidationForm validating the optional Procedure block of worklist create/update requests. Pydantic models mirror the DICOM Requested Procedure module, Performed Procedure Step, and Code Sequence Macro (attribute keys per §6.2 of #54 (closed)). Per FR-3, a facet is valid with a coded sequence and/or a free-text description — code-only and description-only are both first-class; empty facets and unknown facets/attributes are rejected.
sonador_orthanc/worklist/history.py (new) — helpers for the three reserved, server-owned Meta keys (RequestedProcedure, PerformedProcedure, ReviewHistory): strip/extract utilities and build_history_entry (PreviousState/State/User/Timestamp/CommentUID).
sonador_orthanc/worklist/web.py — new WorklistProcedureHistoryMixin applied to both the management (create) and REST (update) views:
- Validates the optional
Procedureblock alongside the existingState/Meta/Commentcontract (FR-1/FR-2) - Strips reserved keys from inbound client
Metaand re-applies the server-owned values, so procedures/history cannot be forged through the generalMetachannel (FR-7) - Appends a
ReviewHistoryentry on item creation and on every status transition; a comment submitted with the transition is saved first so its UID is linked viaCommentUID(FR-4/FR-5) - Reserved keys ride along in the standard worklist
Metaserialization — no serializer change (FR-6)
sonador_orthanc/validation/worklist.py — fixed the latent NameError in WorklistItemValidationForm.clean() (state was read by the completed/cancelled lock check before assignment).
sonador_orthanc/validation/base.py — fixed the validation-error response formatter to stringify pydantic loc entries: list-item errors carry integer indices (e.g. ('ProcedureCodeSequence', 0, 'CodeValue')), which crashed '.'.join(...) during 400-response serialization and surfaced as a 500. First exposed by the malformed Code Sequence rejection test in sonador-ftests!10 (merged); the *CodeSequence validators are the plugin's first list-of-models validation.
sonador_orthanc/web/tag.py — redacted the copied "Performed Procedure step" UPS docstring noted in #41; the module docstring now describes the imaging-tag (Code Sequence Macro) API it actually implements.
Follow-up: worklist authorization no longer requires local Modify
A related fix, uncovered while reviewing this feature's ACL model: worklist create/update previously required local Modify in addition to View + the server-level worklist permission, purely as a side effect of how the Orthanc Advanced Authorization plugin traverses the patient/study ancestor hierarchy (not a deliberate security requirement — Modify is a distinct, more powerful DICOM-data-editing permission). Fixed across:
-
orthanc-authorization(plugin, already onmasteras commit7ac8fb1) -
oak-tree/medical-imaging/sonador!90(lib/orthancapi) - This MR's
sonador_orthanc/auth/web.py(the now-obsolete "worklist exemption" workaround removed from_fetch_patient_policy) - Test updates:
oak-tree/medical-imaging/sonador-client!73,oak-tree/medical-imaging/sonador-ftests!12
Notes
- No columns, tables, or migrations (NFR-1); absence of procedure/history data remains valid, so existing worklist clients are unaffected (NFR-3).
- Functional coverage lives in sonador-ftests!10 (merged) (
tests_ext_worklist_procedures): FR-3 validation including rejection paths, per-transition history withCommentUIDlinks, FR-7 forgery protection, completed/cancelled locks, chronological ordering, the full review arc over both the standard and DICOMweb endpoint families, and NFR-5 ACL parity.
Related to #54 (closed) (do not auto-close: the client history-timeline UI remains open there pending a design round).