Approval queues and expiry
In plain English: some actions on AlphaSwarm are too consequential to happen automatically — placing certain orders, promoting a strategy to live trading, or ingesting a new data source. Those actions go into an approval queue where a human must explicitly say yes. Since August 2026, every queued request also carries an expiry time: if nobody decides within the window, the request lapses instead of waiting around indefinitely. That matters because a "yes" given three days ago may no longer be safe today — markets move, and an approval should describe the world it was granted in.
Which queues exist
| Queue | What waits in it | Decide surface |
|---|---|---|
| Order approvals | Order intents that exceed automatic risk thresholds | Operator UI approvals inbox, /accounts routes |
| Promotion approvals | Research → money-plane crossings | Promotion Gates API, step-up MFA + four-eyes |
| Ingestion approvals | New data-source onboarding actions | Data connector control plane |
All three share the same HITL (human-in-the-loop) mechanics: a request
row with pending status, an audited decision, and — new — a TTL.
How expiry works
Three cooperating mechanisms, so expiry holds even if one lags:
- Enqueue TTL stamp — every new approval row gets
expires_atpopulated from the queue's TTL setting (order_approval_ttl_seconds, mirroringpromotion_approval_ttl_seconds). - Beat sweeper — a guarded Celery beat task
(
alphaswarm/tasks/approval_expiry_tasks.py) periodically flips overduepending → expiredacross all three queues under an advisory lock, emitting one audit event per queue sweep and anorder.approval_expiredlifecycle fact per order. - Decide-time guards — even if the sweeper hasn't run yet, the
approve/reject endpoints check
expires_atat decision time and return HTTP 410 Gone for stale requests;PromotionService.approverefuses equivalently.
Backwards compatibility
Rows created before the feature (with NULL expires_at) are never
default-expired — no data migration re-stamps them. Expiry only
applies to requests enqueued while the feature is active.
Rollout and flags
| Setting | Default | Effect |
|---|---|---|
approval_expiry_enforcement_enabled | off | Master switch for TTL stamping, sweeping, and decide-time guards. |
order_approval_ttl_seconds | per deployment | TTL for order approvals. |
promotion_approval_ttl_seconds | per deployment | TTL for promotion approvals. |
The sweeper is registered in the Celery beat ownership manifest
(configs/celery_beat_ownership.json), so beat-owner drift is caught by
CI rather than at runtime.
Relationship to four-eyes approval
Expiry answers "how long is a pending request decidable?". The four-eyes rule answers "who may decide?" — the approver must be a different person from the requester, and privileged control-plane actions additionally require two distinct approvers recorded in the asctl four-eyes approvals ledger. The two mechanisms compose: a request must be decided by the right people and within its window.
See also
- Promotion Gates API — the promotion queue's endpoints and statuses.
- Promotion evidence — the statistical gates a promotion request must also pass.
- Paper metadata gate — the other startup guard on paper sessions.
- Kill-switch incident response — the emergency halt path that bypasses queues entirely.