Deadlines, escalation and stale decisions
Every action that needs a person has two separate deadlines: one to receive a verified decision, and one for the agent to resume after approval. Neither can outlive the request's own validity or the grant.
How the deadlines are set
| Deadline | Set when | Value |
|---|---|---|
not_after | Submit | The agent's not_after, or 24 hours after submit. |
decision_deadline | Submit, when approval is needed | The earliest of not_after, the grant's expires_at, and now + the shortest decision_ttl_seconds of the required approvals. |
resume_deadline | When the last approval arrives | The earliest of not_after, the grant's expires_at, and now + the shortest resume_ttl_seconds of the requirements. |
resume_deadline | Submit, allowed within a grant | The earliest of not_after, the grant's expiry, and now + 1 hour (only relevant if the action was submitted without immediate execution). |
The status document shows both (decision_deadline, resume_deadline) and expires_at, which is the deadline that matters in the current state. The approval page and the email show the decision deadline.
What happens when a deadline passes
- A
pending_approvalaction past its decision deadline (ornot_after) becomesexpiredwithreason_code: approval_expired; its pending approvals becomeexpired. - An
approvedaction past its resume deadline (ornot_after) becomesexpiredwithreason_code: resume_expired: the approval stood, but the original agent did not come back in time. A grant that expires or is revoked before the agent resumes is reported by the resume recheck instead (see the table below). - Expiry is applied both by the periodic sweep (every 5 minutes; Cron Trigger on Cloudflare, Cloud Scheduler on GCP) and immediately whenever the action is read or resumed, so nobody sees an overdue action as still open.
- An approver opening an overdue request sees "the decision deadline has passed" and cannot decide.
Late and repeated decisions
Every state change is conditional on the current state. A decision that arrives after expiry, denial, cancellation or revocation (a late ServiceNow readback, a replayed webhook, a restored backup) is ignored: it cannot revive a closed record. An expired request needs a new request and a fresh approval.
Progress while pending
While an action is pending_approval, progress tells the agent and the admin where it is stuck:
progress | Meaning |
|---|---|
delivery_pending | Axiom has not yet delivered the request to the approval system (or is retrying). |
waiting_on_person | Delivered; waiting for an approver. |
decision_readback_unavailable | The approval system could not be read back; Axiom retries every 60 seconds. |
awaiting_agent_resume | (state approved) A decision is in; nothing happens until the original agent resumes. |
reconciling | (state outcome_unknown) Axiom is asking the provider for the outcome by operation key. |
approvals[].next_party names who must act next: approval delivery before delivery, then for example finance_approver in axiom or finance_approver in servicenow.
Escalation and alternate approvers
In this release:
- Alternate approvers are every person who holds the required role in the tenant, directly or through an org-level role. All of them are notified, and any eligible one can decide. To add an alternate, give a second person the role.
- There are no escalation chains or multi-stage approvals yet. A request nobody decides simply expires at its deadline, visibly, with
approval_expired. Multi-stage approval and customer-defined escalation are proposed future workflows. - Delivery failures are retried with exponential backoff (up to 8 attempts, at most 15 minutes apart); after that the approval shows delivery
failedin the action timeline.
Stale decisions on resume
An approval is evidence of a decision at a point in time, not permanent authority. When the agent resumes, Axiom rechecks everything before claiming execution:
| What changed since the approval | Result |
|---|---|
| The agent was suspended or retired | revoked (agent_suspended) |
| The credential was revoked | revoked (credential_revoked) |
| The grant was revoked or expired | revoked (grant_revoked), or denied (grant_expired) |
| An emergency deny now applies | revoked (emergency_deny) |
| Policy now denies (for example a new ceiling) | denied with the rule's reason code |
| Policy now needs more approvals | denied (policy_stale) |
| An approver no longer holds the role | denied (approver_ineligible) |
| The agent changed a material field | Refused with 409 conflict (material_change); the action stays approved |
Choosing values
- Make
decision_ttl_secondslong enough for your approvers' working pattern (the sample uses 4 hours) but shorter than the grant. - Keep
resume_ttl_secondsshort (the sample uses 1 hour): it is the window in which an approved but unexecuted request is live. - Remember the agent's own
not_aftercaps both.