Task lifecycle and assignment¶
Workflow tasks (approvals, document submissions, user prompts, etc.) acquired a runtime ownership / hold / comment surface in the LSA-8721 epic. This page summarises the new behaviour so portal approvers, admins, and integration callers can use it without re-reading the implementation PRs (#460, #461, #462, #463).
Lifecycle states¶
Every workflow_step row now exposes an assignment_state field
alongside its existing execution status. The two are independent:
the execution status (pending / running / waiting_approval /
waiting_response / completed / etc.) is still owned by the engine,
while assignment_state describes who is currently working the task
in the inbox UI.
assignment_state |
Meaning |
|---|---|
unassigned |
Nobody owns the task yet. Eligible approvers can self-claim it; admins / task:assign callers can assign it to a specific user. |
assigned |
A user has been assigned but hasn't started yet. Reaching the task as that user shows the row in their inbox. |
in_progress |
The current assignee has actively claimed the task and is working it. Other users (even other eligible approvers) cannot complete / respond / approve until ownership changes. |
on_hold |
The task is paused with an optional explanation. Non-admin callers cannot complete / respond / approve until the hold is released. |
Transitions:
unassigned→in_progressviaPOST /api/tasks/:id/claim.unassigned/assigned/in_progress→assignedviaPOST /api/tasks/:id/assign(requirestask:assign).- any non-terminal →
unassignedviaPOST /api/tasks/:id/unassign(requirestask:assign). - any non-
on_hold→on_holdviaPOST /api/tasks/:id/hold(the assignee or atask:assigncaller). on_hold→assigned(orunassignedif no assignee remains) viaPOST /api/tasks/:id/unhold.
Terminal execution statuses (completed, failed, skipped,
cancelled) freeze the lifecycle — the assignment fields become
informational and the lifecycle endpoints return 409 for further
mutations.
Approval semantics are unchanged¶
Runtime claiming is an authorization boundary, not a change to the
existing approval-completion model. A multi-row approval step
(approvers: ["user:abc", "group:helpdesk"]) still finalises only
when EVERY row reaches a non-pending decision — the AND-of-list
contract enforced by the workflow engine. Claiming the task simply
prevents two eligible approvers from racing each other on the same
row — once user A claims, user B sees a 403 on
POST /api/approvals/:id/decide until the claim is released or the
task is reassigned.
Multi-approver "any-of" / quorum semantics are tracked in issue #237 and are explicitly not delivered by LSA-8721.
Comments¶
Each task row has its own comment thread under
/api/tasks/:id/comments. Visibility and moderation are split into
two orthogonal capabilities:
canViewDeleted— see soft-deleted rows (with the body redacted tonull). Admin,task:assign, andtask:comment_managecallers all qualify.canModerate— edit or soft-delete comments authored by other users. Admin andtask:comment_manageonly. The author can always edit / soft-delete their own comment.
Comment bodies persist on the row but are intentionally never copied
into audit metadata. Audit entries (task.comment_added,
task.comment_edited, task.comment_deleted) carry the task id, an
actor, a bodyLength, and a byAuthor flag — never the body itself.
Permissions¶
Two permissions were added in PR #460 and are seeded automatically:
task:assign— assign / reassign / unassign / hold / release- hold any task. Granted toadmin(every permission) andresource_manager.task:comment_manage— moderate comments authored by other users. Granted toadminandresource_manager.
approver and requestor roles only get the existing
task:complete permission and rely on assignee or eligibility
checks for action authorization.
Audit actions¶
The following audit actions were introduced for the lifecycle epic:
task.claimed/task.assigned/task.unassignedtask.held/task.releasedtask.comment_added/task.comment_edited/task.comment_deleted
All eight redact user-typed free-text content (hold reasons, comment
bodies) from metadata; only identifiers, lengths, and a byAuthor
flag are persisted.
UI surface¶
- The admin task inbox (
/tasksin the admin web app) shows a comments icon and a per-row action menu offering Claim / Assign / Reassign / Unassign / Hold / Release hold next to the existing Complete / Delete affordances. - The portal task inbox (
/tasksin the portal web app) shows the same comments icon and a narrower action menu offering Claim / Place on hold / Release hold. Portal users self-claim and don't see the user-picker assign affordance.