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 Procedure block alongside the existing State/Meta/Comment contract (FR-1/FR-2)
  • Strips reserved keys from inbound client Meta and re-applies the server-owned values, so procedures/history cannot be forged through the general Meta channel (FR-7)
  • Appends a ReviewHistory entry on item creation and on every status transition; a comment submitted with the transition is saved first so its UID is linked via CommentUID (FR-4/FR-5)
  • Reserved keys ride along in the standard worklist Meta serialization — 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 on master as commit 7ac8fb1)
  • 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 with CommentUID links, 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).

Edited by Sonador Claude

Merge request reports

Loading