> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Inbound queue SLA forecast: pre-suggest callback before breach

> How inbound ACD queues forecast a service-level breach from the head's projected wait, pre-suggest the keep-your-place callback opt-in to flagged queue heads before the target is actually missed, and how the per-queue SLA target + per-wave fan-out are operated.

# Inbound queue SLA forecast: pre-suggest callback before breach

Inbound ACD queues forecast a breach of the queue's configured SLA target by comparing the queue head's **projected wait (EWT)** against that target. When the projected wait meets or exceeds the target — while the caller is still short of the actual breach — the head is flagged to be offered the **keep-your-place callback opt-in**: the caller can hang up and get a callback once they reach the front of the queue, without losing their saved position (the callback-in-queue dispatcher dials them back on the Devotel wholesale softswitch).

The forecast is **bounded**: a single evaluation wave flags at most a small, fixed number of queue heads (10), hard-ordered by smallest-positive-EWT first. The closest-to-breach head is flagged before any less-urgent head, so a bounded consumption budget drains the most urgent entries first — breaching queues get a near-term relief lever without flooding every waiting caller.

***

## How the forecast decides

The evaluator wave computes each head's EWT the same way the in-queue EWT-announcer does:

1. **Rolling window stats.** The wave pulls the queue's recent answered wait time and the queue head's aht-ahead rank (the current position of the head inside the queue's ZSET).
2. **Projected wait.** `EWT = (ahead-in-that-rank + 1) × measured AHT (seconds) ÷ agents-available`. When the queue has no recent answered calls (cold start), the helper clamps into a bounded constant and never emits `Infinity`.
3. **Compare against SLA.** If the resulting `EWT ≥ slaTargetSeconds`, the head is a forecast candidate. The flag is pure — the evaluator only *marks* "you should offer the opt-in"; the in-queue press-1 surface and the supervisor-side `POST /api/v1/voice/queues/:id/sla-forecast` advisory route still own the actual offer.
4. **Another pass is a no-op.** If `EWT < slaTargetSeconds`, the head is skipped silently — no flag, no permission, no callback hint.

The wave itself is *bounded*, not one-flag-per-tick. One wave evaluates the heads of every running queue, hard-sorts candidates smallest-EWT-first, and returns the closest 10. A queue with several heads queued all still re-evaluates on the next wave; nothing is persisted across waves, so the same queue head is re-flagged each wave until the caller is served or the head is no longer past target.

## Configure the SLA target

The forecast reads the same per-queue **answer-within** target that feeds SLA-aging, the wallboard service-level metric, and the SLA-breach policy. Without it, the queue is opt-out and no forecast ever fires.

**Dashboard.** Open **Voice → Queues** in the console, select the queue, and set **SLA target (seconds)** (5–300, default 20). This is the same `targetServiceLevelSeconds` knob the [voice-queues guide](/guides/voice-queues) covers. The forecast, the wallboard's SLA numerator, and the SLA-aging engine all resolve it through the same queue config — change it once and every surface adopts the new bound.

**API.** Send the same field the dashboard exposes, as a partial update on the queue:

```bash cURL theme={null}
curl -X PUT "https://api.orbit.devotel.io/api/v1/voice/queues/queue_supp" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "targetServiceLevelSeconds": 30
  }'
```

If you *also* run the queue-entry gate (`slaCallbackPolicy`), the same `targetServiceLevelSeconds` is the threshold that drives `ok / suggest / block`. The forecast's pre-suggestion keeps working even when you only run one of the two gates.

<Warning>
  The forecast is opt-in per queue and only becomes live when `targetServiceLevelSeconds` is set. A queue with no SLA target is never foreclosed — the feature is strictly non-intrusive on legacy traffic. Queues whose admins only configure the gate policy never get a supervisor flag unless they also set a target.
</Warning>

## Pre-requisites and effective behavior

* **SLA target set.** Without `targetServiceLevelSeconds`, the queue collapses to `ok` on every surface — no pre-suggestion and no supervisor flag.
* **Statistical window.** The projected wait relies on the queue's *answered-call* window window (the same `offeredCalls / answeredWithinSla` sample the wallboard tick publishes). A queue with no recent answered traffic falls back to a default handle-time proxy, so the forecast is still correct in posture; it only mistakes for "breaching" once the rolling window saturates.
* **Agent availability.** When `agentsAvailable` is zero, the EWT math intentionally degrades to `Infinity` (the queue-entry gate reads this as the worst posture) and the supervisor advisory treats "0 heads available" as its own no-suggestion signal. Forecasts degrade predictably, not silently.
* **Opt-in scope.** `slaCallbackPolicy` is *not* the gate the pre-suggestion uses — the forecast is purely advisory; the entry gate remains a separate opt-in for operators who want to refuse entry, not just flag a callback.

## Operation and monitoring

* **Supervisor surface.** Flagged heads surface through the live queue feed (`GET /api/v1/voice/queues/{id}/live` SSE) and through the same diagnostic read the [voice-queues guide's SLA breach policy section](/guides/voice-queues) describes. The advisory endpoint `POST /api/v1/voice/queues/{id}/sla-forecast` returns the queue's forecast + a suggestion-action label (`no_action` / `pre_suggest_callback` / `breach_in_progress`), which the wallboard port wires to a "press 1 for a callback" hint.
* **Wave cadence.** The forecast evaluator runs on the queue wave scheduler (the same cadence the rest of the ACD wave runs, not a new endpoint) and flags up to the bounded fan-out per wave. There is no per-request API the queue head must trip.
* **Webhook/audit.** The pre-suggestion itself is *internal* — the queue's `callback-suggestion` mark feeds the existing in-queue callback opt-in and the audit surface that the queue head's forecast makes visible. Operators who want it routed outbound should instrument it via the existing [alert rules](/guides/voice-queues) (`metric: sla_pct`, `op: lt`, `action: webhook`) rather than expect a new event envelope.
* **Relationship to press-1.** The flagged opt-in is the **same** queue in-queue callback opt-in offered by the manual press-1 escape path; the forecast simply raises the offer before the breach (similar headroom math, same dispatcher). A caller who ignores the pre-suggestion still retains the manual option at any point while waiting.

## Edge cases

* **No history.** No recent answered calls → the helper falls back to a bounded `avgHandleSeconds` constant (60s default via `MAX_CALLBACK_EWT_SECONDS` clamp) and the forecast still returns correctly; this is intentional so a cold-start queue still pre-warns after its first answer.
* **No SLA configured.** Queue without `targetServiceLevelSeconds` → the `slaTargetSeconds` parameter is `undefined`, the helper's guard stops the candidate, and the queue's forecast is always `no_action`. Your dashboard reflects this as "SLA target not set."
* **Disabled callback.** If the queue has callback dispatch disabled (no `callbackRequests`/in-queue escape wired), the pre-suggestion still fires on the queue — it merely can't be honored by the caller. Operators should disable SLA target on queues that don't want the surface.
* **Second wave.** Nothing is persisted across waves. On the next wave the same queue head re-flags if the EWT remains ≥ target, and later-flagged heads continue to be re-flagged in earlier-to-later order until they drain.
* **Queue = 0.** A queue with depth zero but whose service-level is already under target resolves as `alreadyBreached` on the supervisor advisory; the in-wave pre-suggestion guard skips since there is no queue head to offer to.
* **Head never reaches front.** The flag's decision point is at enqueue/evaluation. The head may age past the SLA before a pre-suggestion offer lands; that is the expected forecast-lead: it offers about the breach-before-it-happens window, not a fresh breach event.

## Troubleshooting

* **SLA breached, no pre-suggestion appeared.** Confirm (a) the queue actually *has* `targetServiceLevelSeconds` set, (b) the queue has at least one head with `EWT ≥ slaTargetSeconds`, (c) the head hasn't already been flagged this wave, and (d) the `agentsAvailable` count reported at `GET /api/v1/voice/queues/{queueId}/stats` is non-zero — a zero number yields a forecast no-suggestion rather than a freezing flag.
* **Pre-suggestion fired but the callback was never offered.** The dispatcher's pre-suggestion is *advisory*: the in-queue press-1 surface and the `handleOverflow(call, 'callback', ...)` gate still decide whether to voice the offer. If the in-queue callback chain is misconfigured the flag is still marked but no callback path is wired — set the queue's `slaCallbackPolicy` to `suggest` or `block` and wire the entry gate so the mark reaches the dispatcher.
* **It looks like the forecast is stuck on a queue head.** The bounded wave flag does not remove a queue entry; the helper only marks the offer the queue-head can use. If the head never drains, the offer keeps being recomputed on every wave until either capacity arrives or the caller overflows/terminates.

## Related

* [Set up and run voice queues](/guides/voice-queues) — create the queue, the SLA-breach policy surface, and the alert rules the forecast's diagnostics ride on.
* [Wallboard alarm rules](/guides/wallboard-alarm-rules) — the supervisor alert surface that already draws on the same `sla_pct` service level the forecast forecasts.
* [Inbound queue SLA forecast + virtual callback gate](/voice/queue-sla-forecast-callback) — the sibling gate that blocks/reroutes entries at the queue-entry check rather than flags them for the callback opt-in.
* [Voice queues API reference](/api-reference/endpoints/voice) — the queue update endpoint and the diagnostic read (`/queues/{id}/stats`, `analytics`, `heatmap`) used to validate the forecast's inputs.
