ADR-0064: Per-Document Workflow Role Bindings (Author / Reviewer / Releaser), Enforced¶
- Status: accepted
- Date: 2026-07-13
- Deciders: Nicolas Burri ("I agree with all your recommendations for D1 to D4"), motivated by his company QMS: it defines author/reviewer/releaser per document but does not enforce them at release time — "the idea itself sounds attractive… we'd need the option to allow for multiple roles in each of the three groups."
- Builds on: the (scope, type) review policy (V013, REQ-LC-004/006: per-transition role
permissions, (role, min-count) approval requirements, four-eyes) — already ENFORCED by
LifecycleService; and the ADR-0053 pattern (type policy pre-fills, document editable). - Relates to: ADR-0054 (unstaffed-role visibility), ADR-0030 (declarative policy snapshot), ISO 13485 §4.2.3 (documents approved by designated authority — per-document designation is the cleanest reading).
Decision¶
- Three per-document role groups — AUTHOR, REVIEWER, RELEASER — each holding one or more catalog roles. REVIEWER entries may carry a min-approver count (≥ 1).
- D-1a — copy-then-independent: creating a draft copies the type review policy's submit/approve/release role sets (and matching min-counts) onto the document; from then on the DOCUMENT bindings are authoritative for that document's workflow and are edited there. The type policy remains the template for future documents (and keeps governing the non-workflow transitions: REVOKE, CANCEL, PERIODIC_REVIEW).
- D-2a — edit window: bindings are editable while DRAFT by users holding the document edit permission; every change is audited (before/after shape, AuditChanges). Frozen at submit — the review round runs against the pinned set (bindings join the existing submit pin); changing reviewers mid-review = reject/withdraw and resubmit.
- D-3a — enforcement teeth, no silent fallback: SUBMIT requires all three groups non-empty (400 with a clear message). A group whose roles have zero ACTIVE holders effective in the document's scope shows the ADR-0054 unstaffed warning at edit time and BLOCKS the transition that needs it. There is no fallback to bare scope permissions — a fallback is precisely the non-enforcement being replaced.
- D-4a — author semantics: AUTHOR roles gate SUBMIT only. Editing stays governed by the scope edit permission (collaborative drafting keeps working); accountability attaches where the regulatory act happens. REVIEWER roles gate APPROVE (with min-counts), RELEASER roles gate RELEASE.
- Four-eyes is layered on top unchanged (submitter ≠ approver, regardless of roles). The review inbox ("awaiting your approval") routes by the DOCUMENT's reviewer bindings.
Consequences¶
- Additive migration (per-document binding table; RLS via the document's scope like every document-anchored table); pre-production reseed populates bindings via copy-on-create (ADR-0058 — no data migration).
LifecycleService.requireTransitionreads document bindings for SUBMIT/APPROVE/RELEASE; separation tests extend to the new table; the seeded matrix gains binding cases (four-eyes × bindings, unstaffed block, freeze-at-submit).- UI: the draft metadata head gains three role-group selectors (addressee-select pattern); the detail rail shows the groups with unstaffed flags.
- REQ rows (define/enforce/freeze semantics) enter at the v1.7 baseline (registered).
Amendment 1 (2026-08-13) — birth shapes freely, established shapes are controlled (register #90)¶
His question on the clean system: any EDIT_DRAFT holder could change a document's workflow rows — including who releases. His own framing carried the decision: setting up a NEW document's workflow is part of authorship and feels right; a writer contributing to an ESTABLISHED document rerouting the release away from the QMB does not. He also considered and himself refuted the releaser-held alternative: rights held by the current releaser self-lock — a wrongly-set releaser could only be corrected by someone holding the wrong role.
The rule: while a document has never had a released version, EDIT_DRAFT holders set all three workflow rows freely (unchanged — setup is authorship). Once ANY version has ever been released — including since-superseded or revoked ones; the predicate is "a release has ever happened", never "one currently stands" — the rows are part of the controlled process shape, and changing them requires CONFIGURE_REVIEW_POLICY effective in the scope.
The audit story this buys: §4.2.3's defined approval responsibility becomes structurally
preventive (the system refuses the reroute) instead of detectively compensated (the trail
would have shown it). Reflection equals enforcement: the workflow view carries
mayEditBindings + bindingsLocked, and the draft editor's selects state the reason in
place when disabled — never a hidden control, never an unexplained one.