Durable approval record for a governed tool proposal.
Mirrors the ReviewTask idiom exactly (D15-01..04):
- Denormalized
statusenum for read-your-writes - Last-decision fields (
decided_by,last_decision,decided_at,reason) - Transitions co-committed with an append-only
ToolActionEventin one transaction - One-active-lane enforced by a partial unique index on
tool_proposal_id WHERE status = 'pending'(APRV-04)
Append-Only Invariant
This schema is insert-only for the approval record itself. Status transitions are
written via decision_changeset/6 which updates the denormalized fields. There is no
update/1 or delete/1 function — the ToolActionEvent trail is the immutable audit log.
Status Axis (D15-02, D16-08)
The approval status axis is separate from ToolProposal.status:
:pending— awaiting operator decision (one active lane enforced by partial unique index):approved— operator approved; resume worker will re-validate and transition to:execution_pending:execution_pending— re-validation passed;ToolExecutionWorkerenqueued (Phase 16):rejected— operator rejected with reason (FLOW-03):deferred— operator deferred with reason (FLOW-03):expired— TTL elapsed; dual mechanism (scheduled Oban job + lazy guard at resume time):invalidated— re-validation failed; policy/scope changed since approval:executed— Phase 16 success terminal;run/3returned{:ok, result}and outcome co-committed:execution_failed— Phase 16 failure terminal; exhausted retries or permanent re-validation failure
Summary
Functions
Standard changeset for creating or updating a ToolApproval.
Requires: tool_proposal_id, status.
Status defaults to :pending.
Registers the partial unique index constraint for one-active-lane enforcement (APRV-04).
Decision changeset for transitioning an approval to a new status.
Returns the locked status values for ToolApproval.
Functions
Standard changeset for creating or updating a ToolApproval.
Requires: tool_proposal_id, status.
Status defaults to :pending.
Registers the partial unique index constraint for one-active-lane enforcement (APRV-04).
Decision changeset for transitioning an approval to a new status.
Parameters:
approval— the existingToolApprovalstructstatus— the new status atomdecision— free-form decision label (e.g."approved","rejected")reason— operator-provided reason; REQUIRED for:rejectedand:deferred(FLOW-03)actor_id— the actor making the decisiondecided_at— timestamp of the decision
Enforces FLOW-03: reason is required for :rejected and :deferred transitions.
Returns the locked status values for ToolApproval.