6. Runtime View¶
The architecturally significant flows are documented below as they land. Diagrams are text (Mermaid, per the house rule). Two flows are written; the rest stay as candidates (TBD).
6.1 DIRECT single-person record release (ADR-0091)¶
A record type may be configured for a DIRECT release flow (review_policy.release_flow,
V062), letting an authorized role holder release straight from DRAFT with no review round —
the friction-free path for meeting notes, cloud-verification records, and other "proof the
process ran" evidence. The flow is permitted only for RECORD-category types; PRESCRIPTIVE
and TEMPLATE types cannot be set to DIRECT (server- and schema-enforced structural floor,
ADR-0091 §3). It is a policy-permitted transition, not a new state — everything downstream
(effectivity, retention, disposal, acknowledgement, training fan-out, audit) is unchanged.
release_flow (STANDARD/DIRECT) is orthogonal to the pre-existing release_mode
(AUTOMATIC/EXPLICIT, V013): the former decides whether the submit→approve ceremony exists at
all, the latter only qualifies a STANDARD flow's release trigger (ADR-0091 clarification).
sequenceDiagram
actor R as Releaser (holds a RELEASER role)
participant API as api (DirectRelease endpoint)
participant LS as document · LifecycleService.directRelease
participant GATE as ReleaseGate
participant DOC as document · content freeze
participant DB as PostgreSQL (RLS)
participant EV as lifecycle · DomainEventPublisher
participant NOT as notification
R->>API: POST /api/documents/versions/{id}/direct-release {effectiveFrom?}
API->>LS: directRelease(userId, versionId, effectiveFrom)
LS->>DB: runAs(userId) — open RLS-scoped transaction
Note over LS: guards, all inside the one transaction
LS->>LS: state == DRAFT ? (else 409)
LS->>LS: policy.releaseFlow == DIRECT ? (else 409)
LS->>LS: caller holds the document's RELEASER binding ? (else 403, ADR-0064)
LS->>GATE: evaluate comments-resolved + training-questionnaire gates
Note over GATE: approvals gate is N/A — there is no review round
LS->>DOC: freezeContent — frozen blobs + manifest, body-searchable
LS->>DB: mirror in-text doc: links as system `references` (ADR-0051)
LS->>DB: markReleasedFromDraft(effectiveFrom ?? now) — DRAFT→RELEASED
LS->>DB: audit RELEASED (DRAFT→RELEASED, change reason/impact pinned)
LS->>EV: publish VersionReleased (in-transaction)
EV->>NOT: acknowledgement / training fan-out (unchanged)
A document on a DIRECT-configured type may still be routed through the full submit→approve flow
by choice — DIRECT permits, it never forbids (ADR-0091 §2). The getVersion action reflection
advertises directRelease with an honest applicable/allowed/reason, computed by the same
WorkflowActionEvaluator seam that enforces the transition, so the advertised availability and
the server's decision can never diverge (§8.10).
6.2 Recurring-obligation sweep (ADR-0089 / ADR-0094)¶
Recurring QMS duties (cloud verification, backup rehearsals, environment checks) are modelled as
per-scope recurring_obligation rows (V063). Their completion evidence is a newly RELEASED
record of the designated document type in the scope — often DIRECT-released (the ADR-0091
synergy) — so no separate "mark done" act exists. Due/overdue status is derived, never stored
(§8.10): a scheduler sweep raises inbox tasks, and reconciles them the moment a completing release
lands.
sequenceDiagram
participant T as api · RecurringObligationScheduler (every instance ticks)
participant DB as PostgreSQL
participant FN as lqms_sweep_recurring_obligations (SECURITY DEFINER)
participant INBOX as responsible-role holders' inboxes
T->>DB: pg_try_advisory_xact_lock(key) — one instance wins, others skip
Note over T,DB: idempotent regardless of the lock; the lock only avoids wasted concurrent work
T->>FN: call with p_now (runs as the function owner, across ALL scopes)
Note over FN: EXECUTE revoked from public — only the owner-connection scheduler may run it
FN->>DB: RAISE — for each ACTIVE obligation whose due window is open,<br/>insert one OBLIGATION_DUE task per responsible role
Note over FN: next-due delegated to lqms_obligation_next_due (V070) per schedule kind INTERVAL / MONTHLY / YEARLY,<br/>day-clamped "never too late" (ADR-0094): a FOLD over the completion history (the effective RELEASED records of<br/>the completion type, in order) from created_at — each completion discharges the occurrence outstanding at its moment
FN->>DB: RESOLVE — mark DONE any OPEN OBLIGATION_DUE task whose obligation<br/>is no longer in-window (fresh completion), is now inactive,<br/>or whose assignee role is no longer responsible
DB-->>INBOX: OBLIGATION_DUE tasks surface (ADR-0038/0039 pattern)
Idempotency is in the SQL (a not-exists guard + a partial unique index on the OPEN task), so N
concurrent ticks cannot double-raise even if the lock is lost. OBLIGATION_DUE is not manually
resolvable (like PERIODIC_REVIEW_DUE): it clears only through a completing release the sweep
reconciles. The sweep writes no per-raise audit row (matching the periodic-review sweep); the
obligation's lifecycle events and each completion (the RELEASED event) are the audited record.
The Kotlin oversight derivation (RecurringObligationService, over an injected clock) uses the
same next-due arithmetic as this sweep — since V069 literally the same SQL function
(lqms_obligation_next_due), so the parity contract (§8.10, ADR-0089 §3 / ADR-0094 §7) is
structural rather than merely test-pinned. The function is pure computation and takes the
completion history as an argument (V070), so each side enumerates the completing records with its
own visibility — the sweep as the owner across all scopes, the derivation under the caller's RLS —
while the RULE stays in one place. The verdict thresholds stay in Kotlin: DUE_SOON opens
due_window_days before the occurrence (the same predicate the sweep raises on), and OVERDUE
begins only the day AFTER a calendar occurrence — the due day is inclusive, since a completion
filed on it counts (ADR-0094 §4). INTERVAL keeps its instant deadline.
6.3 Candidate scenarios (TBD)¶
- Document creation → review → release (standard four-eyes life-cycle walkthrough)
- Document revocation
- Orphan-blob GC — quarantine → rescue-on-re-reference / purge-after-expiry (ADR-0092; the system-context sweep is summarized in §8.4)
- Search query (RAG + LLM round trip)
- Backup creation and restore (mechanically documented in §7.1)
- Project setup with role configuration