---
title: "SupportOps"
slug: supportops
category: business
term_status: established
evidence_status: partially_verified
summary: "SupportOps (support operations) designs and runs the system behind customer support: intake, triage and routing, SLA clocks, staffing and schedules, helpdesk tooling, quality and metrics, so customers get predictable answers at a sustainable cost."
audience: [Beginners, Support leaders and support ops managers, Workforce management analysts, Helpdesk administrators and engineers, Product and engineering leaders]
last_verified: 2026-10-23
key_takeaways:
  - "SupportOps is the operations function behind customer support: it owns the queue, the clocks, the staffing model, the tooling and the measurements, not the individual answers."
  - "\"Support operations\" is an established role family; the one-word label is informal, and the SupportOps / CustomerOps / CXOps split used here is this Atlas's editorial distinction."
  - "Staffing is queueing maths: offered load = arrivals × handle time, and the extra agents you need above that load to hit a service level come from randomness, not effort (Erlang C)."
  - "An SLA is only as honest as its clock: business or calendar hours, pause rules, whether an autoreply counts, and whether unanswered tickets are in the denominator change the result more than the team does."
  - "Count re-contacts, not claimed resolutions: a bot or a macro that closes conversations can look excellent while customers come back on another channel."
  - "Escalation to engineering is a designed interface with a template, a severity rubric and a feedback loop, not a forwarded email."
related: [customerops, cxops, knowledgeops, itops, incidentops, revops, chatops, llmops]
---

## What SupportOps is

### In 30 seconds

**SupportOps (support operations) is the discipline of designing and running the system that customer support works inside:**
how requests arrive, how they are classified and routed, which clock each one is measured against, how many people are needed in
each half hour, which tools and automations they use, how quality is checked, and how the numbers reach the people who can fix
the causes. Support agents answer customers; SupportOps makes sure the right agent gets the right ticket at the right time, with
the knowledge and tools to solve it, and that leaders can see whether the promise to customers is being kept.

A short way to hold it: support is a **queue** (work arriving at random), measured by **clocks** (service levels), improved through
**loops** (insight flowing back to product, knowledge and staffing). SupportOps owns all three.

Written for beginners, support ops managers, workforce management analysts, helpdesk administrators, and the product and
engineering leaders who receive escalations. Sources were last verified on **2026-10-23**.

::: note Scope of this page
This page treats SupportOps as the operations of **reactive, ticket-centred customer support** for external customers. Proactive
customer success is on [CustomerOps](../customerops/); journey-wide feedback and survey design are on [CXOps](../cxops/); the
internal IT service desk is on [ITOps](../itops/). That three-way split is an **editorial distinction** of this Atlas, explained in
[What SupportOps is not](#what-supportops-is-not-naming-and-boundaries).
:::

### At a glance

| Question | Answer |
|---|---|
| Goal | Predictable response and resolution times at a sustainable cost, with customer insight reaching the teams that can remove the causes |
| Who does it | Support operations managers and analysts, workforce management (WFM) analysts, helpdesk administrators, QA leads, support tooling engineers |
| Scope | Channels and intake, triage and routing, tiers and escalation, SLA policies, macros and automation, self-service and AI agents, quality assurance, staffing and scheduling, support data and reporting |
| Not in scope | Account health and renewals ([CustomerOps](../customerops/)), survey design and journey-wide feedback ([CXOps](../cxops/)), the knowledge practice itself ([KnowledgeOps](../knowledgeops/)), production incident command ([IncidentOps](../incidentops/)) |
| Prerequisites | None. Basic spreadsheet skills help; the labs use Python's standard library |
| Key outputs | SLA policies, routing rules, staffing plans and schedules, a metric dictionary, QA scorecards, an escalation interface, a change log for the helpdesk |
| Term status | **Established** as "support operations" (a recognised team and job family); the one-word "SupportOps" is informal and has no standards body |

### The problem it solves

Without an operations layer, a support team that grows from five people to fifty usually hits the same walls, in roughly this
order:

1. **Nobody can say how many people are needed.** Headcount requests are argued from anecdote ("we are drowning") rather than
   from volume, handle time and a stated service level. The answer arrives after the backlog does.
2. **Clocks disagree.** One report says 92% of tickets got a first reply within eight hours, another says 61%. Both are right: one
   counts business hours and lets an autoreply stop the clock; the other counts calendar hours and waits for a human.
3. **Work lands on whoever looks first.** The hardest tickets sit untouched because everyone cherry-picks easy ones; specialists
   answer password resets while integration problems wait.
4. **The helpdesk becomes an archaeological site** of triggers and macros nobody can explain.
5. **Insight leaks.** The same bug is reported 300 times, solved 300 times, and engineering hears about it from a sales call.
6. **Cost rises faster than volume**, because every new channel and every new product line gets its own queue and its own
   staff, and pooled capacity is lost.

SupportOps is the response: treat support as a service system with demand, capacity, routing rules and feedback loops, and give
someone the job of designing and running that system.

### What SupportOps is not: naming and boundaries

- **Not the support team.** Agents and support engineers resolve customer problems. SupportOps designs their environment. A
  vendor blog captures the remit well: support operations as "a team of seasoned experts dedicated to providing your agents with
  the tools they need to do their job".[^zd-blog] In a small company the same person does both, and that is fine.
- **Not CustomerOps or CXOps (editorial distinction).** The labels overlap in the market: "customer operations" is used as an
  umbrella for all customer-facing operations, as a synonym for support operations, and for customer success operations. This
  Atlas assigns reactive service (tickets, SLAs, queues) to SupportOps, proactive post-sale success (health scores, renewals) to
  [CustomerOps](../customerops/), and measurement and governance across the whole journey to [CXOps](../cxops/). No standard
  defines this boundary; it is a way to teach each part once.
- **Not ITOps.** The internal IT service desk uses the same queueing maths and similar tools, but it serves employees, works inside
  IT service management practices (incident, request, problem, change), and is taught on [ITOps](../itops/).
- **Not incident management.** When production is down, an incident commander runs the response on
  [IncidentOps](../incidentops/). SupportOps runs the customer side: mass-ticket handling, status messages and the link between
  hundreds of tickets and one engineering incident.
- **Not the knowledge practice.** Support is the largest producer and consumer of knowledge, but Knowledge-Centered Service
  (KCS) and article lifecycle are taught on [KnowledgeOps](../knowledgeops/). This page owns the self-service *channel* and its
  deflection metrics.

## Where SupportOps comes from and where it sits

### Origins and evolution

The practices are older than the label. Telephone call centres created the core problem (random arrivals, expensive staff, a
promise about waiting time) and an academic field grew around it: forecasting, staffing, scheduling and routing are a well-studied
area of operations research.[^aam07] The staffing mathematics goes back to A. K. Erlang's work on telephone traffic; a 2007 survey
notes that the square-root safety-staffing rule "was first observed by Erlang (1948) and was later formalized by Halfin and Whitt
(1981)".[^aam07] Professional bodies grew up around the support centre: HDI's support-centre manager course, for example, covers
service level management, performance results and workforce management.[^hdi-scm] International standards followed for contact
centres (ISO 18295, 2017) and for complaints handling (ISO 10002).[^iso18295-1][^iso10002]

Three shifts produced the modern support operations role: **software helpdesks** turned every ticket into timestamped data, so
clocks and routing became configuration; **digital and asynchronous channels** broke the single phone queue into many queues with
different clocks; and **technical products** put support next to engineering, so someone had to own that interface.

The job title followed: GitLab's public handbook, for example, shows a "Support Operations" unit and a team that owns the support
tooling, now called "Customer Support Systems" (see [Use case 1](#use-case-1-support-operations-as-a-systems-team-at-gitlab-documented)).[^gl-support][^gl-css]

### Glossary and mental model

| Term | Meaning | Why it matters |
|---|---|---|
| Ticket / case / conversation | One customer request and its history | The unit of work |
| Triage | Classifying a request: type, product area, priority, language | Wrong triage means wrong queue and wrong clock |
| Routing | Assigning work to a queue or agent by rules (skills, capacity, priority) | Who works on what, in which order |
| Tier (L0–L3) | L0 self-service, L1 front line, L2 specialists, L3 engineering or product experts | Each tier adds a queue |
| Swarming | Bringing the right people to a case instead of escalating it through tiers | Alternative to tiers for complex work |
| SLA policy | Targets per priority for reply, update and resolution clocks | The promise, encoded in the tool |
| OLA | Operational level agreement between internal teams (for example support and engineering) | Makes the internal half of an SLA visible |
| First reply time (FRT) | Time from creation to first public reply (tools differ on what counts) | The most common SLA metric |
| Requester wait time | Time the customer is waiting for you (pauses while you wait for them) | Close to the customer's experience |
| AHT | Average handle time: talk or work time plus wrap-up per contact | Drives staffing directly |
| Offered load | Arrivals per minute × AHT in minutes, in erlangs | The minimum number of busy agents the work needs |
| Service level (SL) | Share of contacts answered within a target time, such as 80% in 20 seconds | The live-channel clock; its definition matters |
| Shrinkage | Paid time when agents cannot take contacts (breaks, training, absence) | Turns "agents needed" into "agents to schedule" |
| Occupancy | Handling time ÷ (handling time + idle time) | Too high burns people out; too low wastes money |
| FCR | First contact resolution: solved without the customer coming back | Hard to measure; best proxied by re-contact |
| Deflection | A customer solving the problem without creating a ticket | Easy to over-claim; measure with re-contact |
| Macro, trigger, automation | Saved reply; event-driven rule; time-driven rule | Consistency, and where hidden behaviour lives |
| Backlog | Open tickets waiting for agent action, usually with an age profile | The asynchronous waiting queue |
| WFM | Workforce management: forecasting, staffing, scheduling, intraday control | The capacity half of SupportOps |

#### A mental model: a queue, a clock and a loop

- **Queue.** Requests arrive at random; capacity is people × time. When arrivals briefly exceed capacity a queue forms, so every
  design question (how many people, pooled or specialised queues) is a queueing question first.
- **Clock.** Each ticket carries clocks with start, pause and stop rules. The SLA is the promise; the clock definition decides
  whether you can see if you kept it.
- **Loop.** Every ticket is evidence about a defect, a confusing screen, a missing article or a wrong forecast; SupportOps turns
  it into fixes, articles and better forecasts.

### How SupportOps relates to other Ops

::: figure SupportOps among its neighbours: what flows across each boundary
```mermaid
flowchart TB
  CX["CXOps: journey-wide feedback, survey design"]
  SUP["SupportOps: tickets, SLAs, routing, staffing"]
  CO["CustomerOps: health, renewals, success plans"]
  KO["KnowledgeOps: KCS articles, runbooks"]
  INC["IncidentOps: production incidents"]
  PR["Product and engineering"]
  IT["ITOps: internal IT service desk"]
  CX -->|survey method| SUP
  SUP -->|ticket insight| CX
  SUP -->|escalations, risk signals| CO
  SUP <-->|capture and reuse| KO
  INC -->|status, ETA| SUP
  SUP -->|bugs, requests| PR
  IT -.->|shared queueing maths| SUP
  classDef core fill:#e8f3f2,stroke:#16756f,color:#122029
  classDef neutral fill:#f1f4f6,stroke:#5b7a87,color:#122029
  class SUP core
  class CX,CO,KO,INC,PR,IT neutral
```
Text equivalent: SupportOps sits in the middle. CXOps supplies survey method and receives ticket insight. SupportOps sends
escalations and risk signals to CustomerOps, exchanges knowledge with KnowledgeOps (capturing articles while solving and reusing
them), receives status and estimated fix times from IncidentOps during outages, and sends bugs and feature requests to product
and engineering. ITOps is a sibling that uses the same queueing maths for internal users (dashed line).
:::

| Neighbour | Shared scope | SupportOps focus | Neighbour's focus | Hand-off |
|---|---|---|---|---|
| [CustomerOps](../customerops/) | Existing customers | Reactive requests, SLAs | Health scores, renewals, success plans | Ticket trends and escalations feed health scores |
| [CXOps](../cxops/) | CSAT and feedback | Transactional CSAT after a ticket | Survey design, NPS/CES, journey-wide loop | CXOps sets method; SupportOps applies it |
| [KnowledgeOps](../knowledgeops/) | Articles, KCS | Self-service channel, deflection metrics | Knowledge lifecycle, KCS practice | Agents capture and improve articles in the flow of work |
| [IncidentOps](../incidentops/) | Outages | Mass tickets, customer status, problem linking | Incident command, mitigation, reviews | Liaison role; one incident ↔ many tickets |
| [ITOps](../itops/) | Ticket queues, SLAs | External customers | Internal IT service desk, ITSM practices | Same staffing maths; different users and processes |
| [RevOps](../revops/) | Customer data in the CRM | Support data model, entitlements | Revenue definitions, GTM stack decision rights | Entitlements and account data flow from the CRM |
| [ChatOps](../chatops/) | Chat-driven work | Customer messaging channels | Operating systems through team chat | Escalation alerts often land in team chat |
| [LLMOps](../llmops/) | AI answers | Governance of AI agents in support | Operating LLM applications (evaluation, retrieval) | SupportOps sets resolution and safety rules; LLMOps runs the system |

## Principles and operating model

### Charter and principles

The charter below is **this Atlas's proposal**; no industry body publishes one for SupportOps.

::: decision Proposed SupportOps charter
**Mission.** Make customer support predictable for customers, sustainable for the people who do it, and useful to the rest of the
company.

**Measurable goals.** SLA attainment by priority with unanswered tickets counted; re-contact rate within seven days; backlog age;
cost per resolved ticket by channel; QA score; time from repeated ticket pattern to engineering ticket.

**Non-goals.** SupportOps does not set product priorities, own renewals, or design company-wide surveys. It does not chase
utilisation for its own sake.
:::

Principles, each with the trade-off it accepts:

1. **Define the clock before you set the target.** Start, pause and stop rules, business or calendar hours, and what counts as a
   reply are written down before anyone promises "four hours". Trade-off: slower first SLA launch.
2. **Pool capacity unless a skill really differs.** Queueing maths rewards pooling (Lab 2); split queues only for language,
   regulated data or genuinely different skills. Trade-off: some loss of specialisation.
3. **Measure outcomes the customer would recognise.** Re-contact and requester wait time beat "tickets closed" and "assumed
   resolutions". Trade-off: harder data work.
4. **Every rule has an owner and a reason.** Triggers, automations, macros and routing rules are changed through a change log, like
   code. Trade-off: some admin overhead.
5. **Protect people from the maths.** Occupancy near 100% is possible only briefly; schedules that assume it burn out the
   team.[^koole] Trade-off: higher cost per contact.
6. **Escalation is an interface, not a favour**: template, severity rubric, internal target and feedback channel. Trade-off:
   engineering must agree to an OLA.
7. **Automation must be reversible and visible.** Every bot or macro answer can reach a human, and every automated close can be
   reopened. Trade-off: lower headline deflection.

### Fundamentals and building blocks

| Building block | What it contains | Typical owner |
|---|---|---|
| Channel and intake design | Which channels exist, hours, forms and required fields, identity and entitlement lookup | SupportOps with support leadership |
| Taxonomy | Ticket types, product areas, reasons, priorities, tags | SupportOps (data owner) |
| Routing and queues | Skills, groups, capacity rules, queue order, overflow | SupportOps |
| SLA and OLA policies | Targets per priority and customer tier; internal targets with engineering | Support leadership approves; SupportOps encodes |
| Workforce management | Forecasts, staffing models, schedules, intraday adjustments | WFM analyst (inside SupportOps or alongside) |
| Agent tooling | Macros, side panels, integrations (CRM, billing, issue tracker), AI assistance | SupportOps / support tooling engineers |
| Self-service and AI agents | Help centre, community, bots, their hand-off rules | SupportOps with [KnowledgeOps](../knowledgeops/) |
| Quality assurance | Scorecards, sampling, calibration, coaching inputs | QA lead |
| Data and reporting | Metric dictionary, dashboards, warehouse exports | SupportOps analyst |
| Change management | Requests, testing in a sandbox, release notes, rollback | SupportOps |

### Roles, ownership and RACI

Common roles (titles vary): support operations manager; systems administrator or analyst for the helpdesk; support tooling
engineer (integrations, scripts, apps); WFM analyst (forecasting and scheduling); QA lead; support data analyst; trainer.
Use case 1 shows how one company documents the systems part.

The RACI below is **this Atlas's proposal** for a mid-sized organisation (R = responsible, A = accountable, C = consulted,
I = informed).

| Activity | Support ops mgr | WFM analyst | Helpdesk admin | Support team leads | Head of support | Engineering lead |
|---|---|---|---|---|---|---|
| SLA policy targets | R | C | C | C | A | I |
| Encoding SLAs and clocks in the tool | A | I | R | I | I | I |
| Volume forecast and staffing plan | C | R | I | C | A | I |
| Schedules and intraday changes | I | R | I | A | I | I |
| Routing rules and skills | A | C | R | C | I | I |
| Macros and automations | A | I | R | C | I | I |
| Escalation template and OLA | R | I | C | C | A | C |
| Bug triage of escalations | C | I | I | C | I | A, R |
| QA scorecard and calibration | A | I | I | R | C | I |
| Metric dictionary and dashboards | A, R | C | C | C | I | I |
| AI agent rules and hand-offs | A, R | C | R | C | C | C |

The engineering lead is accountable for triaging escalations because only engineering can decide what a defect is; support is
accountable for the quality of the escalation it sends.

### The ticket lifecycle

Most helpdesks use a variant of the same statuses. Zendesk's are New, Open, Pending (waiting for the customer), On-hold (waiting for
a third party), Solved and Closed, and its SLA metrics are defined by which statuses each clock counts.[^zd-sla][^gl-metrics]

::: figure Ticket statuses (which clocks run in each is explained below)
```mermaid
stateDiagram-v2
  [*] --> New: arrives
  New --> Open: picked up
  Open --> Pending: ask customer
  Pending --> Open
  Open --> OnHold: third party
  OnHold --> Open
  Open --> Solved
  Solved --> Open: reopen
  Solved --> Closed: after N days
  Closed --> [*]
```
Text equivalent: a request arrives as New and becomes Open when an agent picks it up. From Open it can go to Pending when the
agent asks the customer something (back to Open when the customer replies), to On-hold while waiting on a third party such as
engineering (back to Open when answered), or to Solved when the agent solves it. Unlabelled arrows are these returns and the solve. A solved ticket can be reopened by the customer or closes automatically
after a set number of days. In Zendesk's definitions, requester wait time counts New, Open and On-hold; agent work time counts New
and Open; total resolution time counts everything until Solved.
:::

The lifecycle matters because each status is also a clock rule. In Zendesk, requester wait time "starts when the ticket is created
and stops once the ticket is solved. It pauses when the ticket has a Pending status", while total resolution time does not pause
except in Solved.[^zd-sla] A team that parks tickets in Pending to stop a clock improves one metric and harms the customer; the
assurance checks later on this page look for exactly that.

### Operating model and governance

A workable cadence (this Atlas's proposal; adjust to volume):

| Cadence | Forum | Inputs | Decisions |
|---|---|---|---|
| Every 15–30 minutes (live channels) | Intraday check | Arrivals vs forecast, queue length, agents available | Move people between channels, delay breaks, open overflow |
| Daily | Queue stand-up | Backlog by age and priority, breaches, escalations waiting | Reassign, swarm, chase engineering |
| Weekly | Support operations review | SLA attainment, re-contact, QA, forecast error, top contact reasons | Staffing changes, routing fixes, top-5 problem list to product |
| Monthly | Service review with engineering and product | Escalation volume and age, defect themes, deflection results | OLA changes, bug priority, article gaps |
| Quarterly | Capacity and SLA planning | Forecast, hiring lead time, price/plan changes | Headcount, SLA tiers, channel hours |

## Architecture and workflow

### Reference architecture

The architecture below is a process-and-systems view, vendor-neutral. Boxes are capabilities; one product may provide several.

::: figure Reference architecture of a support operation
```mermaid
flowchart TB
  CH["Channels: email, form, chat, phone, in-app"]
  ID["Intake: identity, account, entitlement"]
  SS["Self-service and AI agent"]
  TR["Triage: type, product area, priority"]
  RT["Routing: skills, capacity, queue order"]
  AG["Agents: L1 front line, L2 specialists"]
  ESC["Escalation to engineering issue tracker"]
  KB["Knowledge base"]
  WFM["Workforce management: forecast, schedule"]
  AN["Data and reporting: metric dictionary"]
  CH --> ID
  ID --> SS
  SS -->|needs a human| TR
  TR --> RT
  RT --> AG
  AG -->|defect or expert need| ESC
  ESC -->|fix, workaround| AG
  KB --> SS
  AG -->|capture, improve| KB
  WFM -->|staffed capacity| RT
  AG -->|events, timestamps| AN
  AN -->|actuals| WFM
  classDef core fill:#e8f3f2,stroke:#16756f,color:#122029
  classDef neutral fill:#f1f4f6,stroke:#5b7a87,color:#122029
  class TR,RT,WFM,AN core
  class CH,ID,SS,AG,ESC,KB neutral
```
Text equivalent: requests arrive through channels and pass intake, which identifies the customer and their entitlement.
Self-service and an AI agent try the knowledge base; anything needing a human goes to triage and then routing, which uses skills,
staffed capacity and queue order to assign an agent. Agents escalate defects to the engineering issue tracker and get fixes or
workarounds back, and they improve knowledge articles. Workforce management supplies staffed capacity to routing; events flow to
data and reporting, whose actuals feed the next forecast. Triage, routing, workforce management and data are highlighted as the
capabilities SupportOps designs most directly.
:::

Design notes for each component:

- **Intake** should resolve identity and entitlement before routing. Routing by plan or contract needs that data, and the SLA
  policy usually depends on it.
- **Triage** can be done by form design, rules, agents or a classifier; whatever does it, the taxonomy must stay small enough to
  be used consistently.
- **Routing** decides **which queue** (skills, language, customer tier) and **which order** inside it (oldest first, priority, or
  nearest SLA breach); see the [triage and routing playbook](#playbook-triage-and-routing).
- **Escalation** crosses a trust and tooling boundary. The support ticket stays the customer-facing record; the engineering issue is
  the defect record; they are linked, and the support side owns customer communication.
- **Reporting** needs the event history (status changes with timestamps), not just the final state of each ticket; SLA clocks and
  re-contact cannot be rebuilt from final states.

**Alternatives.** A small team can run everything inside one helpdesk. A large or regulated operation often adds a WFM platform,
a QA tool and a data warehouse, and manages the helpdesk configuration as versioned code. Outsourced front lines add a second organisation and an ISO 18295-2-style client relationship.[^iso18295-2]

### End-to-end workflow: happy path and exception path

::: figure From first contact to fix: a request that escalates to engineering
```mermaid
%%{init: {"sequence": {"actorMargin": 24, "width": 110, "messageMargin": 30, "noteMargin": 6, "diagramMarginX": 8}}}%%
sequenceDiagram
  autonumber
  participant B as AI agent
  participant C as Customer
  participant A as L1 agent
  participant S as L2 expert
  participant E as Engineering
  C->>B: problem
  B->>C: article
  C->>B: not solved
  Note over B,A: hand-off + transcript to L1
  A->>C: asks for logs
  C->>A: logs
  A->>S: escalates
  S->>E: files defect
  E-->>S: workaround
  S-->>A: workaround, ETA
  A->>C: workaround, ETA
  E-->>S: fix shipped
  S-->>A: fix live
  A->>C: confirms, solves
```
Text equivalent: the customer describes a problem to an AI agent, which suggests an article. The customer says it is still broken,
so the AI agent hands the conversation to the L1 agent with the transcript on the ticket (the note in the diagram). The L1 agent sends the first reply and asks for logs; the customer
sends them. The L1 agent escalates to an L2 expert (a specialist) using the escalation template, and the specialist files a defect in
engineering's tracker linked to the ticket. Engineering returns a workaround now and a fix in a later release; the specialist
passes this to the L1 agent, who gives the customer the workaround and an expectation. When the fix ships, engineering tells the
specialist, the specialist tells the L1 agent, and the L1 agent confirms with the customer and solves the ticket.
:::

**Happy path.** Most tickets never leave L1: routed to the right skill, answered with a reviewed macro or article, solved in one
or two exchanges, not reopened.

**Exception paths** SupportOps must design explicitly:

| Exception | Detection | Designed response |
|---|---|---|
| Bot cannot help, customer asks for a person | Hand-off intent, repeated question, negative sentiment | Hand-off with transcript; no forced loop back to the bot |
| Ticket in the wrong queue | Agent re-routes; re-route rate per category | Fix the triage rule; measure re-routes weekly |
| SLA about to breach | Clock alert (time-based automation) | Notify lead; queue ordering by nearest breach |
| Many tickets about one cause | Spike in a category; agent flags | Link as incidents to one problem ticket; status message; see [IncidentOps](../incidentops/) |
| Engineering does not answer | Escalation age past OLA | Escalate to engineering manager; visible in the monthly service review |
| Customer goes silent while Pending | Pending age | Reminder automation, then solve with a reopen window |

For mass issues, Zendesk's problem/incident model is a concrete mechanism: link each incident ticket to one problem ticket, and
solving the problem solves the linked incidents and copies the solving comment; Zendesk advises to "Refrain from solving any of
the incident tickets directly".[^zd-prob]

## Capacity: the queueing maths behind every SLA

This part is the centre of gravity of the page. Most support arguments ("we need more people", "the SLA is unrealistic", "AI will
halve the team") are capacity questions, and they can be answered with a few formulas and honest inputs.

### Offered load, Little's law and the shape of demand

**Offered load** is the arrival rate multiplied by the average handle time, in the same time unit. Koole's call-centre handbook
describes it as "the number of agents needed to be able to handle all incoming calls" if nothing were random; because arrivals
cluster and handle times vary, you need more.[^koole] Example from that book: 100 contacts forecast for a 15-minute interval with
an AHT of 3 minutes 30 seconds gives λ = 100 ÷ 15 = 6.67 contacts per minute and a load of 6.67 × 3.5 = 23.33 erlangs, so at
least 24 agents must be busy just to keep up.[^koole]

**Little's law** links the three quantities every backlog report shows: L = λW, where L is the average number of items in the
system, λ the average arrival rate and W the average time an item spends in the system.[^little] It is a theorem, not a rule of
thumb, and it needs no assumption about the arrival pattern. For support it gives two quick checks:

- 400 tickets a day that each stay open 1.5 days on average imply an average backlog of 600 open tickets.
- To bring the average time open down to 0.5 days at the same arrival rate, the average backlog must fall to 200. A team that says
  "we will cut resolution time by two-thirds" without planning to hold one-third of today's backlog has not yet made a plan.

**Demand has shape.** Volumes follow time-of-day, day-of-week and annual patterns, plus events (releases, outages, billing runs,
holidays). In a textbook data set of five-minute call volumes to a North American commercial bank, Hyndman and Athanasopoulos show a
strong daily pattern and a weaker weekly one, with Mondays tending to be busier.[^fpp-calls] Staffing therefore works per interval
(usually 15 or 30 minutes), not per day.[^koole]

### Erlang C: from load to agents

The **Erlang C** model (a queue with Poisson arrivals, meaning contacts arrive randomly and independently at a steady average rate;
exponential handle times; identical agents; first come first served; no hang-ups) gives the probability that a contact waits, the average speed of answer (ASA) and the service level for a given number
of agents.[^aam07] In words: compute the load A; for N agents above A, the probability of waiting P(wait) comes from the Erlang C
formula; the share answered within t is 1 − P(wait) × e^(−(N − A) × t ÷ AHT); and ASA = P(wait) × AHT ÷ (N − A). Lab 2 implements
it in about twenty lines and reproduces Koole's numbers.

For Koole's example (load 23.33 erlangs), Lab 2 gives 20.6% answered within 20 seconds with 24 agents, 62.0% with 26 and 83.0%
with 28; Koole reports "only around 21%" at 24 agents and that 28 agents are needed for 80% in 20 seconds.[^koole]

Four lessons follow, all visible in Lab 2:

1. **The cliff.** With 24 agents (just above the load) the queue barely works; four more agents change service from terrible to
   good. Small staffing errors at high load produce large service errors.
2. **Non-linear sensitivity.** A 10% longer AHT moves the requirement from 28 to 31 agents; 20% more volume moves it to 33.
3. **Pooling.** Two separate queues of 50 contacts per interval need 30 agents in total; one shared queue needs 28. Every split
   (by product, by plan, by language) costs capacity; split only when the skill or the rule really differs.
4. **Economies of scale.** At the same 80/20 target, 25 contacts per interval need 9 agents (65% occupancy) and 1,000 need 243 (96%
   occupancy). The safety margin grows roughly with the square root of the load, the "square-root safety-staffing rule" that
   operations research traces from Erlang to Halfin and Whitt.[^aam07] Large pools reach occupancy people cannot sustain for long;
   Koole notes that occupancy near 100% "can only occur for short periods".[^koole]

::: caution Where Erlang C is wrong
The model "ignores blocking and customer abandonments"; Erlang A adds impatient customers.[^aam07] Koole warns that ignoring
abandonment can produce large prediction errors, "especially in underload situations".[^koole] Lab 4 simulates the same queue:
without hang-ups the simulation matches Erlang C within a point, but if callers hang up after an average of three minutes, 26
agents already reach 85% in 20 seconds, at the price of 4.2% of callers abandoning. Erlang C tends to over-staff when callers
abandon, and abandonment is itself a failure. Multi-skill routing, time-varying arrivals and concurrent chats also break the
assumptions; use simulation or WFM software.
:::

### Service level: one name, several formulas

"80% answered within 20 seconds" is so common that Koole calls it the "industry standard" in quotation marks, while noting that
other targets are possible.[^koole] What matters more is the **formula**. Koole gives three ways to count abandoned contacts in
the service level and a worked example: 510 contacts, 460 answered (410 within 20 seconds), 50 abandoned (30 of them within 20
seconds) give 89%, 85% or 80% depending on the definition.[^koole] The first definition ignores abandoned calls; it "clearly gives
a perverse incentive" because a long-waiting caller who hangs up improves the number.[^koole] Write the formula into the metric
dictionary and report the abandonment rate next to it. Koole reports that abandonment limits are "often in the order of 3 or
5%"; treat that as common practice, not a target.[^koole]

### Shrinkage, occupancy and schedules

Erlang C answers "how many agents must be **available** in this interval". People also take breaks, attend training and coaching,
are sick or on holiday. **Shrinkage** is the share of paid time not available for contacts; Koole writes that "A shrinkage of 40%
is not exceptional".[^koole]

- Agents to schedule = agents needed ÷ (1 − shrinkage). With 28 needed and 35% shrinkage, schedule ⌈28 ÷ 0.65⌉ = 44.
- **Occupancy** = handling time ÷ (handling time + available idle time).[^koole] It falls out of the staffing, so it should be
  monitored rather than targeted: pushing occupancy up by under-staffing degrades service and wears people out.
- Koole also points out a trap: lower first contact resolution *raises* occupancy, because repeat contacts fill the idle time.[^koole]
  Occupancy that rises while re-contact rises is bad news dressed as efficiency.

Schedules turn interval requirements into shifts, breaks and days off. Doing this well (part-time shifts, split shifts, break
placement, overtime rules, labour law, preferences) is the job WFM software and analysts exist for; the mathematics is covered in
the operations research literature on scheduling and rostering.[^aam07]

::: figure The workforce management loop: from history to tomorrow's schedule
```mermaid
flowchart TB
  H["History: volume and AHT per interval"]
  F["Forecast: volume and AHT, with events"]
  R["Required agents per interval (Erlang C, simulation, workload)"]
  SH["Add shrinkage: agents to schedule"]
  SC["Schedule: shifts, breaks, skills"]
  ID["Intraday: compare actuals, adjust"]
  V["Variance review: forecast error, adherence"]
  H --> F
  F --> R
  R --> SH
  SH --> SC
  SC --> ID
  ID --> V
  V -->|update models and events| H
  classDef core fill:#e8f3f2,stroke:#16756f,color:#122029
  classDef decision fill:#fdf3e3,stroke:#c9800f,color:#122029
  class F,R,SH,SC core
  class ID,V decision
```
Text equivalent: history of volume and handle time per interval feeds a forecast that includes known events. The forecast turns
into required agents per interval (Erlang C for live channels, simulation or workload calculations otherwise), then into agents to
schedule after shrinkage, then into a schedule of shifts, breaks and skills. During the day, intraday management compares actuals
with the plan and adjusts. A variance review measures forecast error and schedule adherence and updates the models and event list,
which closes the loop back to history.
:::

### Asynchronous work: email, forms and backlog

Erlang C fits contacts that wait in a live queue for seconds or minutes. Email and web-form tickets wait for hours, and agents can
defer them, so the working model is **workload plus a backlog constraint**:

1. Workload hours = tickets × AHT. Example: 1,200 emails a week at 9 minutes = 180 hours.
2. Productive hours per agent = contracted hours × (1 − shrinkage) × the share of available time you can realistically spend on
   tickets. Example: 40 × 0.65 × 0.85 ≈ 22.1 hours, so 180 ÷ 22.1 ≈ 8.1, which rounds up to 9 agents for the average week.
3. Check the **clock**, not just the average: if the SLA is a first reply within 8 business hours, the team must clear each
   morning's overnight arrivals before they age out. Model the hourly arrivals against hourly capacity, or simulate.
4. Check the **backlog** with Little's law: if 240 tickets arrive per business day and the target average time to first reply is
   4 business hours (half a day), the average number awaiting a first reply must stay near 120.

Blended agents (live chat plus email) let email absorb idle time between chats; Koole's book treats channel blending as its own
staffing problem.[^koole] The risk of blending is that email clocks breach silently whenever chat is busy; give email its own
clock alerts.

**Global coverage.** Customers in several time zones raise two design choices. *Follow-the-sun* pools one queue across regional
teams, which gains the pooling effect above, but needs a written handover (open urgent tickets, promised updates, live incidents)
at each shift change. *Regional queues* keep language and local hours, at the cost of smaller pools. Either way, business-hour
clocks need the right time zone and holiday calendar per region: in Zendesk, a schedule has one time zone, holidays count as
outside business hours, and more than one schedule needs an Enterprise plan (as of October 2026).[^zd-sched]

### Forecasting demand

A support forecast is a time series with several seasonalities and many interventions. Practical guidance:

- Forecast **volume and AHT** separately, per channel and per interval; AHT changes with product releases and new agents.
- Keep an **event calendar**: releases, price changes, billing runs, marketing campaigns, known outages, holidays. Most large
  forecast misses in support are events nobody told the WFM analyst about.
- Start with simple, explainable methods (seasonal naive, exponential smoothing, regression with event dummies) and measure them;
  *Forecasting: Principles and Practice* covers these and multiple seasonality with a call-centre example.[^fpp-calls]
- Track **forecast error and bias** per interval and per day. A forecast that is right on average but wrong at 9:00 on Mondays still
  breaches the SLA at 9:00 on Mondays.
- Forecast the **effect of deflection** conservatively (Lab 3 shows claimed deflection overstating real deflection).

## Practices, frameworks and tools

### Core practices and playbooks

Each playbook lists the goal, the steps and the acceptance criteria. Owners follow the RACI above.

#### Playbook: triage and routing

**Goal:** every ticket reaches the right queue with the right priority within minutes, without agents cherry-picking.

1. Design the **intake form** first: required fields for product area and impact, a severity question in customer language
   ("Is your production system down?"), attachments for logs. Every field you require removes a triage step; every field you add
   lowers completion.
2. Keep the **taxonomy small**: one contact-reason field with 15–40 values, owned by SupportOps, reviewed quarterly. A reason list
   with 300 values is not used consistently, so it measures nothing.
3. Write a **priority rubric** in observable terms (impact × urgency), not in emotions. Example: urgent = production unusable for
   many users with no workaround; high = major function impaired, workaround exists; normal = question or minor defect; low = feedback.
4. Encode **routing**: queue by skill and language, order by nearest SLA breach for queues with SLAs, assign by spare capacity or
   round robin; set a skills timeout so that, once it expires, a ticket can go to agents without the optional skills instead of
   waiting for the one expert. In Zendesk, required skills never time out; the defaults are one hour for email and 30 seconds for
   messaging and calls, in calendar hours; skills-based routing needs a Professional plan or above, and ordering by SLA breach a
   Team plan or above (as of October 2026).[^zd-route]
5. Measure **re-routes** (tickets moved between groups) by reason; a high re-route rate for one category means the rule or the
   form is wrong.

**Acceptance:** re-route rate stable and low; no queue where the oldest ticket is much older than its SLA; agents rarely choose
their own tickets.

#### Playbook: SLA policy design

**Goal:** a promise customers understand, measured by a clock that cannot be gamed.

1. **Pick the metrics.** First reply time is the usual starting point. For resolution, Zendesk's guidance is to "Pick only one
   resolution time metric" among requester wait time, agent work time and total resolution time.[^zd-sla] Add a periodic-update
   target for long-running tickets so customers are not left in silence.
2. **Define the clock.** Business or calendar hours per priority (urgent tickets usually run on calendar hours); which statuses
   pause it; what stops it. In Jira Service Management these are explicit start, pause and stop conditions.[^jsm-cond]
3. **Decide what counts as a reply.** Tools disagree. In Zendesk, first reply time ends at the first public comment from an agent
   "(or autoreply)"; Zendesk notes that reply-time metrics are fulfilled by a trigger that autoreplies with a public comment, and that
   "Autoreplies are available with the Copilot add-on only". SLA policies themselves need Suite Growth or Support Professional and
   above (as of October 2026).[^zd-sla] Freshdesk does not count replies sent by its automation "Send Reply" action, which are "treated as
   system-generated messages rather than agent responses".[^fd-sla] An autoreply that stops the SLA clock measures your autoreply,
   not your service (Lab 1 shows attainment jumping from 5/8 to 8/8).
4. **Make priority reliable.** In Zendesk, SLA targets depend on the system Priority field; a ticket with no priority gets no SLA,
   so a trigger should set one at creation.[^zd-sla]
5. **Order policies** from most to least restrictive when a tool applies the first match.[^zd-sla]
6. **Pair the SLA with an OLA** for escalations: if support promises a periodic update every 24 hours on urgent defects,
   engineering must commit to an internal update cadence.
7. **Report attainment with open tickets included.** Tickets still waiting past target are breaches now, not when they are finally
   answered.

**Acceptance:** written clock definition per metric; a sample of 20 tickets re-timed by hand matches the tool; breached-but-open
tickets appear on the daily report.

#### Playbook: macros, triggers and automations

**Goal:** consistency without hidden behaviour.

- Know the two engines. In Zendesk, ticket triggers "run every time a ticket is created or updated", while automations are
  time-based and "run every hour on all your tickets that are not closed".[^zd-trig] Order and conditions matter: two triggers
  that both set priority will fight.
- **Naming and ownership:** prefix by purpose (`route.`, `notify.`, `sla.`), one owner per rule, a one-line reason in the
  description, and a change log entry for every edit.
- **Test before production:** use a sandbox or a test brand with synthetic tickets that exercise each path; keep the test cases.
- **Review macros on a schedule.** A macro is a cached answer; when the product changes, it is wrong in hundreds of replies at
  once. Give each macro an owner or article, review usage quarterly and retire unused ones. Prefer fewer, explicit rules: if
  nobody can explain why a ticket was routed somewhere, the rules have outgrown their governance.

#### Playbook: self-service and deflection

**Goal:** customers solve what they can solve alone, and reach a person easily when they cannot.

Gartner reported in 2019 that "Only 9% of customers report resolving their issues completely via self-service", and that its poll
of service leaders found live channels cost an average of $8.01 per contact against about $0.10 for self-service; it advised
managing self-service "like a product".[^gartner-ss] The figures are from 2019 and have not been re-measured here; this Atlas treats
them as directional design guidance: self-service is cheap per contact but often incomplete, so its quality decides whether it
saves money or just adds a step before the ticket.

1. Start from **contact reasons**: the top ten reasons by volume are the self-service backlog.
2. Write or fix articles with the agents who answer those tickets; the knowledge practice behind this (KCS) is on
   [KnowledgeOps](../knowledgeops/).
3. Put **search and suggested articles** in the contact form, not only in a help-centre homepage.
4. Measure **deflection honestly**: a session counts only if the customer does not contact you on the same topic within a window
   (seven days is common). Report claimed and verified deflection side by side (Lab 3).
5. Keep a **visible way to reach a person**. Hiding the contact option raises measured deflection and lowers trust.

#### Playbook: quality assurance

**Goal:** catch what clocks miss: wrong answers, poor tone, policy breaches, missed escalations.

1. A **scorecard** of 5–8 criteria tied to outcomes (template in [Templates](#templates)).
2. **Sampling:** random per agent per week, plus targeted samples (reopened tickets, low CSAT, escalations, AI agent hand-offs).
3. **Calibration:** reviewers score the same tickets monthly and discuss differences; without calibration, QA scores measure the
   reviewer.
4. **Use for coaching and system fixes**, not only for individual ratings. A criterion that fails across many agents points to a
   macro, a policy or a product problem.

#### Playbook: escalation to engineering

**Goal:** engineers get reproducible problems once; customers get honest updates.

1. **Template** (see [Templates](#templates)) with impact, linked tickets, reproduction steps and requested severity.
2. **Severity rubric shared with engineering**, and an OLA for acknowledgement and update cadence per severity.
3. **One defect, many tickets:** link tickets to the engineering issue (and in Zendesk to one problem ticket), so the fix can be
   communicated to all affected customers at once.[^zd-prob]
4. **Feedback both ways:** engineering marks "not a defect / needs more info / duplicate" with a reason; SupportOps tracks the
   rejection rate per team as a quality signal for escalations.
5. **Top-problems list** to product monthly, ranked by tickets, customer impact and time spent, not by who shouts loudest.

#### Playbook: tiers or swarming

Tiers (L1 front line, L2 specialists, L3 engineering) are the default. The Consortium for Service Innovation, which advocates the
alternative called Intelligent Swarming, says the tiered model is efficient "if the majority (95% or more) of issues are simple and
known, and resolved during the customer's first contact", and that tiers create "organizational silos and handoffs/escalations that inhibit the exchange of information and
knowledge" and multiple queues.[^swarm] Swarming keeps one owner per case and brings skilled people to it instead of passing it
down a chain.

| Choose tiers when | Choose swarming (or a hybrid) when |
|---|---|
| Most issues are known and repeatable | Many issues are new, complex or span products |
| Front-line turnover is high and training is short | Experts are few and needed across queues |
| Cost per contact is the main constraint | Time to resolution of hard cases is the main constraint |
| Outsourced L1 with clear scope | In-house teams with shared tooling and culture |

A hybrid is common: tiered handling for known issues, swarming for new or high-impact cases. The [decision framework](#decision-framework)
includes this choice.

### Methods, standards and frameworks

Separate what is **normative** (you must comply because you chose to be certified or a contract requires it) from **frameworks**
(optional practice guidance) and **models** (mathematics).

| Item | Type | What it covers | Use it for |
|---|---|---|---|
| ISO 18295-1:2017 | International standard (certifiable) | "service requirements for customer contact centres", in-house and outsourced, all channels; specifies KPIs "as and where required"; confirmed in 2023[^iso18295-1] | Contact-centre management system and audits |
| ISO 18295-2:2017 | International standard | Requirements for organisations using contact-centre services[^iso18295-2] | Contracting and governing outsourced support |
| ISO 10002:2018 | International guidelines | "guidelines for the process of complaints handling"[^iso10002] | Complaint process design |
| COPC CX Standard | Proprietary industry standard | "a performance management system used to improve operations that support the customer experience";[^copc] Release 8.0 (current as of October 2026) adds "New requirements for AI ethics, technology planning, and performance verification", and all certifications use it from January 2027[^copc-r8] | Performance management, outsourcer certification, governance of AI agents |
| KCS v6 | Practice framework (Consortium for Service Innovation) | Solve Loop and Evolve Loop for knowledge in service work[^kcs] | Knowledge capture and reuse; taught on [KnowledgeOps](../knowledgeops/) |
| Intelligent Swarming | Practice framework (same Consortium) | Collaboration model replacing tiered escalation[^swarm] | Complex-case handling |
| Queueing models (Erlang C, Erlang A, Little's law) | Mathematics | Staffing, waiting, backlog[^aam07][^little] | Capacity planning |
| ITIL 4 practices | IT service management framework | Incident, problem, request, service desk | Internal IT service desks; see [ITOps](../itops/) |

None of these defines "SupportOps". ISO 18295 is the closest thing to a requirement set for a contact centre; the standard's full
text is paid and was not read for this page, so no clause-level claims are made here.

### Tooling landscape

Vendor-neutral categories first, examples second. Product names are examples verified to exist (as of October 2026), not
recommendations; no prices are compared except where quoted from the vendor with a date.

| Category | Job it does | Examples | Selection criteria | Lock-in and risk |
|---|---|---|---|---|
| Helpdesk / ticketing | Tickets, channels, SLA clocks, business rules, macros, reporting | Zendesk, Freshdesk, Jira Service Management, Salesforce Service Cloud, HubSpot Service Hub, Help Scout; open source Zammad (AGPL-3.0), osTicket (GPL-2.0), FreeScout (AGPL-3.0), Chatwoot[^zammad][^osticket][^freescout][^chatwoot] | Clock definitions match yours; API and export of full event history; sandbox; routing model | Configuration lives in the vendor; export rules, macros and history regularly |
| Routing and WFM | Forecasts, schedules, intraday, capacity-aware routing | Helpdesk-native routing (for example Zendesk omnichannel routing; Jira Service Management Workforce Management); dedicated WFM suites (for example NICE, Verint, Calabrio, Assembled)[^zd-route][^jsm-wfm] | Interval granularity, multi-skill support, schedule rules for your labour law | Forecast models can be opaque; keep your own baseline |
| Knowledge and self-service | Help centre, community, search, article lifecycle | Helpdesk-native help centres, documentation platforms | Search quality, analytics on failed searches, link from tickets to articles | Content portability (export format) |
| AI agents and agent assist | Automated answers, drafting, summarisation, classification | Helpdesk-native AI, Intercom Fin, others | Definition of "resolution", hand-off quality, audit logs, data use terms | Outcome-based pricing ties cost to the vendor's definition |
| Data and analytics | Warehouse, metric dictionary, dashboards | Warehouse plus BI; see [AnalyticsOps](../analyticsops/) | Event-level data, not only snapshots | Metric definitions drifting between tools |

Capability claims need dates: Atlassian documents that Jira Service Management's Workforce
Management routes work using each agent's "capacity, shift schedule, and availability", that some features need Premium or
Enterprise plans, that the feature "is not HIPAA compliant", and that its routing is "a basic AI feature that consumes Rovo
credits".[^jsm-wfm] Intercom's pricing page offers "Fin AI Agent on all plans for $0.99 per outcome" and, when Fin runs on
another helpdesk, notes "Minimum monthly commitment applies (e.g. 50 outcomes)" (as of 2026-10-23).[^intercom-pricing]

### Automation and AI

The operational question is not "should we use AI" but "which work, measured how, with which guardrails".

**What the evidence says.**

- **Assisting agents.** In a study of 5,172 customer support agents at one firm, access to a generative-AI assistant raised issues
  resolved per hour by 15% on average. Less experienced and lower-skilled agents gained in both speed and quality, while the most
  experienced and highest-skilled saw "small gains in speed and small declines in quality".[^blr] (The 2023 working-paper version
  reported 14% and 5,179 agents.) One firm, one tool: assistance seems to help most where training time is short, and assisted
  answers from experienced agents still need QA sampling.
- **Replacing conversations.** Klarna's 2024 claims for its AI assistant and its 2025 return to hiring human staff are set out in
  [Use case 2](#use-case-2-an-ai-assistant-at-klarna-and-the-human-channel-documented-company-cl). Read together, they describe
  a hybrid, not a full replacement.

**What "resolution" means.** Vendors define it. Intercom counts a resolution when, after Fin's last answer, the customer either
confirms the answer or "exits the conversation without requesting further assistance (assumed resolution)"; a resolution is
deducted if the customer returns to the same conversation.[^fin-outcomes] A customer who gives up and emails instead does not
return to it, so measure AI agents with the same **re-contact window** as self-service (Lab 3: a claimed 87.5% falls to 50%).

**Accountability.** A tribunal has held a company responsible for its chatbot's wrong answer
([Use case 3](#use-case-3-accountability-for-chatbot-answers-at-air-canada-documented-legal-dec)); the general point is
covered on [LLMOps](../llmops/). Treat AI answers on policy, prices, refunds and legal rights as company statements.

**Transparency (EU).** Article 50(1) of the EU AI Act requires **providers** to design AI systems that interact directly with
people so that those people are informed they are interacting with an AI system, unless that is obvious in context; it applies
from 2 August 2026, and a law-firm alert reports it was not delayed by the 2026 AI Omnibus amendment.[^aiact50][^goodwin-50] A
provider develops the system, or has it developed, and places it on the market or puts it into service under its own name or
trademark.[^aiact3] A team
running a vendor's agent is normally a *deployer* and the vendor carries this duty; a company that builds its own agent, or runs
one under its own name, may be the provider. Disclose AI either way as good practice. This is orientation for the EU, not legal
advice.

**Guardrails SupportOps owns** (this Atlas's proposal):

| Guardrail | Why | How to check |
|---|---|---|
| Disclosed as AI; human reachable in one step | Trust; EU AI Act Art. 50(1) where you are the provider | Test script monthly; count "agent" requests that loop |
| Topics the AI must not answer alone (refunds, legal, safety, account security) | Liability (Use case 3) | Hand-off rules; QA sample of AI transcripts |
| Answers grounded in approved, current articles | Stale knowledge becomes confident errors | Article freshness; citation to source in transcript |
| Resolution measured by re-contact, not vendor outcome | Vendor definitions include "assumed" outcomes | Lab 3 method weekly |
| Every automated action reversible and logged | Errors at scale | Audit log review; reopen path |
| Cost per verified resolution, not per claimed resolution | Outcome pricing follows vendor counts | Monthly reconciliation |

Organisations certified to the COPC standard will also meet its Release 8.0 AI-governance requirements.[^copc-r8] Operating the
language-model system itself (evaluation sets, retrieval quality, prompt changes) is covered on [LLMOps](../llmops/); SupportOps
sets the business rules and measures the service.

## SupportOps in practice

### Reference implementation: operating artefacts

The artefacts below are the minimum written system for a support operation of roughly 10–100 people. They are **this Atlas's
templates**; field names in Artefact 1 follow Zendesk's published API, everything else is tool-neutral.

#### Artefact 1: an SLA policy as code (Zendesk API)

Keeping SLA policies in version control makes the clock definition reviewable. Zendesk's SLA Policies API accepts a JSON object
with a `filter` (all/any conditions) and `policy_metrics` (priority, metric, target in minutes, business hours or not); it is
available to administrators on Support Professional or Suite Growth plans and above (as of October 2026).[^zd-sla-api]

Save the JSON below as `sla-policy.json`. It covers every ticket type on tickets tagged `plan_standard` (set, for example, by a
trigger at creation; the tag name is this example's choice); `current_tags` with `includes` is listed in Zendesk's conditions
reference.[^zd-cond] Zendesk's own API example filters on ticket type Incident, which would leave Questions,
Problems and Tasks with no SLA.

_Example status: JSON syntax-checked; not executed (requires a Zendesk account and an OAuth token)._

```json
{
  "sla_policy": {
    "title": "Standard plan - all ticket types",
    "description": "First reply by priority; periodic updates for urgent tickets",
    "filter": {
      "all": [
        { "field": "current_tags", "operator": "includes", "value": "plan_standard" }
      ],
      "any": []
    },
    "policy_metrics": [
      { "priority": "urgent", "metric": "first_reply_time", "target": 60,
        "business_hours": false },
      { "priority": "high", "metric": "first_reply_time", "target": 240,
        "business_hours": true },
      { "priority": "normal", "metric": "first_reply_time", "target": 480,
        "business_hours": true },
      { "priority": "low", "metric": "first_reply_time", "target": 960,
        "business_hours": true },
      { "priority": "urgent", "metric": "periodic_update_time", "target": 240,
        "business_hours": false },
      { "priority": "urgent", "metric": "requester_wait_time", "target": 1440,
        "business_hours": false }
    ]
  }
}
```

_Example status: bash syntax-checked; not executed. Needs an admin's OAuth access token limited to the `sla_policies:write`
scope (for OAuth clients created on or after 30 April 2026, access tokens expire after 30 minutes by default).[^zd-oauth] Replace
`example` with your subdomain; keep the token in an environment variable, never in the repository; run it against a sandbox
first._

```bash
# Create the policy from the reviewed file (token in ZENDESK_TOKEN); --fail-with-body
# (curl 7.76+) makes an HTTP error fail the script and still prints Zendesk's message
curl --fail-with-body "https://example.zendesk.com/api/v2/slas/policies" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${ZENDESK_TOKEN}" \
  -X POST -d @sla-policy.json
```

Review points before applying: treat a created policy as live for matching tickets; it is matched at the list `position` you give
(the last position if omitted);[^zd-sla-api] tickets that match no policy get no SLA at all, so end the list with a catch-all policy
(for example `current_tags` `not_includes` an exemption tag); the policy only applies to tickets that have a system Priority
value, so a trigger must set one; policies apply in order, most restrictive first; autoreplies count as replies for Zendesk
reply-time metrics, so decide whether your autoreply should exist at all.[^zd-sla]

#### Artefact 2: a metric dictionary

One file defines every number on the dashboard. Tool-neutral YAML; the validator checks its syntax.

_Example status: YAML syntax-checked; definitions are this Atlas's proposal._

```yaml
metrics:
  - id: frt_attainment
    name: First reply SLA attainment
    formula: tickets_with_first_agent_reply_within_target / tickets_due_in_period
    includes_open_breaches: true      # unanswered tickets past target count as misses
    autoreply_counts: false
    clock: per priority (urgent calendar hours; others business hours)
    owner: support-ops
  - id: recontact_7d
    name: Re-contact within 7 days
    formula: solved_contacts_followed_by_same_customer_same_reason_7d / solved_contacts
    applies_to: [agent, ai_agent, self_service]
    owner: support-ops
  - id: requester_wait_p80
    name: Requester wait time, 80th percentile (hours)
    formula: p80(time in new, open, on-hold until solved)
    owner: support-ops
  - id: backlog_age
    name: Open tickets by age bucket
    buckets_days: [0-1, 2-3, 4-7, 8-14, 15+]
    owner: support-ops
  - id: csat_transactional
    name: Transactional CSAT
    formula: good_ratings / all_ratings
    report_with: [response_rate, interval_95, n]
    survey_design_owner: cxops
  - id: service_level_live
    name: Live-channel service level (SL2)
    formula: answered_within_t / (answered + abandoned_after_t)
    t_seconds: 20
    report_with: [abandon_rate, asa_seconds]
    owner: wfm
  - id: cost_per_resolved
    name: Cost per resolved contact, by channel
    formula: (people + platform + vendor cost) / contacts_resolved_without_recontact
    owner: support-ops
```

#### Artefact 3: priority rubric and routing rules (tool-neutral)

_Example status: YAML syntax-checked; illustrative configuration to translate into your helpdesk's rule engine._

```yaml
priority_rubric:            # impact x urgency, written in observable terms
  urgent: "Production unusable for many users, no workaround"
  high: "Major function impaired or one user blocked; workaround exists"
  normal: "Question, minor defect, configuration help"
  low: "Feedback, feature request, cosmetic issue"
routing:
  queue_order: nearest_sla_breach   # alternatives: oldest_first, priority_first
  assignment: most_spare_capacity   # alternative: round_robin
  rules:                            # first match wins
    - when: {contract: enterprise, priority: urgent}
      queue: l2-critical
      notify: [support-manager-on-call]
    - when: {language: de}
      queue: l1-german
    - when: {reason: billing}
      queue: l1-billing
      overflow_after_minutes: 30    # design choice, not Zendesk: then l1-general
    - when: {}
      queue: l1-general
capacity:
  email_open_tickets_per_agent: 12
  chat_concurrent_per_agent: 2
```

#### Artefact 4: intake form for a technical product

| Field | Type | Required | Why |
|---|---|---|---|
| Product area | Pick list (10–20 values) | Yes | Routing and reporting |
| What were you trying to do? | Text | Yes | Intent, for triage and search |
| What happened instead? | Text | Yes | Symptom |
| Is a production system affected? | Yes / No | Yes | Drives priority with the rubric |
| How many users are affected? | One / some / all | Yes | Impact |
| Version or environment | Text or detected | If technical | Reproduction |
| Attachments (logs, screenshots) | Files | No | Saves a round trip |
| Contact preference and time zone | Pick list | No | Clock and follow-up |

The form should search the help centre as the customer types the first two answers; that is the cheapest deflection you can build.

### Hands-on labs

Four labs on **synthetic data only**: bash, Python 3.8 or later, standard library only, no accounts and no cost. Each lab was run on
2026-10-23 exactly as printed (Python 3.8.10, Ubuntu Linux, scratch directory); the expected outputs are copied from those runs.

::: warning Do not practise on real customer data
Ticket exports contain personal data and sometimes payment or health information. Use the synthetic files below, or anonymised
data under your company's rules; never copy a helpdesk export to a personal laptop for practice.
:::
#### Lab 1 (beginner): SLA clocks and what they hide

**Objective.** Compute first-reply SLA attainment from a ticket event log in business and calendar hours, see how an autoreply and
unanswered tickets change the result, and compute requester wait time with Pending pauses. **Prerequisites.** bash and Python 3.8+.
**Time.** 25 minutes. **Risk.** None.

1. Create the folder and the data.

_Example status: verified by execution on 2026-10-23 (bash, Linux)._

```bash
mkdir -p ~/supportops-labs/lab1 && cd ~/supportops-labs/lab1
cat > events.csv <<'CSV'
ticket,priority,time,event
T1,urgent,2026-10-12 10:00,created
T1,urgent,2026-10-12 10:00,autoreply
T1,urgent,2026-10-12 10:40,agent_reply
T1,urgent,2026-10-12 10:40,pending
T1,urgent,2026-10-12 13:00,customer_reply
T1,urgent,2026-10-12 13:20,solved
T2,urgent,2026-10-16 16:30,created
T2,urgent,2026-10-16 16:30,autoreply
T2,urgent,2026-10-16 18:10,agent_reply
T2,urgent,2026-10-16 18:10,solved
T3,normal,2026-10-09 16:00,created
T3,normal,2026-10-09 16:00,autoreply
T3,normal,2026-10-12 10:00,agent_reply
T3,normal,2026-10-12 10:00,solved
T4,normal,2026-10-13 09:30,created
T4,normal,2026-10-13 15:00,agent_reply
T4,normal,2026-10-13 15:00,pending
T4,normal,2026-10-14 10:00,customer_reply
T4,normal,2026-10-14 10:30,solved
T5,normal,2026-10-14 08:00,created
T5,normal,2026-10-14 09:20,agent_reply
T5,normal,2026-10-14 09:20,solved
T6,high,2026-10-15 11:00,created
T6,high,2026-10-15 11:00,autoreply
T6,high,2026-10-15 15:30,agent_reply
T6,high,2026-10-15 15:30,solved
T7,low,2026-10-10 12:00,created
T7,low,2026-10-12 11:00,agent_reply
T7,low,2026-10-12 11:00,solved
T8,normal,2026-10-15 16:50,created
T8,normal,2026-10-15 16:50,autoreply
CSV
```

2. Save the script as `sla.py`.

_Example status: verified by execution on 2026-10-23 (Python 3.8.10, standard library)._

```python
"""First-reply SLA and requester wait time from a ticket event log."""
import csv
from collections import defaultdict
from datetime import datetime, timedelta

SNAPSHOT = datetime(2026, 10, 16, 17, 0)   # report run on Friday 17:00
OPEN, CLOSE = 9, 17                         # business hours, Mon-Fri, one time zone
TARGETS = {                                 # priority: (minutes, clock)
    "urgent": (60, "calendar"),
    "high": (240, "business"),
    "normal": (480, "business"),
    "low": (960, "business"),
}


def business_minutes(start, end):
    total, day = 0, start.replace(hour=0, minute=0)
    while day < end:
        if day.weekday() < 5:
            lo = max(start, day.replace(hour=OPEN))
            hi = min(end, day.replace(hour=CLOSE))
            total += max(0, (hi - lo).total_seconds() / 60)
        day += timedelta(days=1)
    return int(total)


def elapsed(start, end, clock):
    if clock == "calendar":
        return int((end - start).total_seconds() / 60)
    return business_minutes(start, end)


tickets = defaultdict(list)
with open("events.csv", newline="") as f:
    for r in csv.DictReader(f):
        when = datetime.strptime(r["time"], "%Y-%m-%d %H:%M")
        tickets[r["ticket"]].append((when, r["event"], r["priority"]))

met_agent = met_auto = met_closed_only = closed = 0
not_due = set()   # no agent reply yet and still inside target: not yet due
print("ticket prio    clock     target  agent-FRT  result   autoreply-counts")
for tid, ev in sorted(tickets.items()):
    ev.sort()
    created, prio = ev[0][0], ev[0][2]
    target, clock = TARGETS[prio]
    agent = next((t for t, e, _ in ev if e == "agent_reply"), None)
    auto = next((t for t, e, _ in ev if e in ("autoreply", "agent_reply")), None)
    frt = elapsed(created, agent or SNAPSHOT, clock)
    ok = frt <= target
    result = ("met" if ok else "BREACH") if agent else ("running" if ok else "BREACH*")
    if result == "running":
        not_due.add(tid)
        print(f"{tid:6} {prio:7} {clock:9} {target:6}  {frt:9}  {result}")
        continue
    ok_auto = auto is not None and elapsed(created, auto, clock) <= target
    met_agent += ok
    met_auto += ok_auto
    if agent:
        closed += 1
        met_closed_only += ok
    print(f"{tid:6} {prio:7} {clock:9} {target:6}  {frt:9}  {result:8} "
          f"{'met' if ok_auto else 'BREACH'}")

n = len(tickets) - len(not_due)   # tickets due: replied, or past target unanswered
print(f"\nNot yet due (running), left out of every rate : {len(not_due)}")
print(f"Attainment, agent reply, open breaches counted: {met_agent}/{n}")
print(f"Attainment, replied tickets only              : {met_closed_only}/{closed}")
print(f"Attainment, autoreply counts as a reply       : {met_auto}/{n}")
cal = sum(elapsed(ev[0][0], next((t for t, e, _ in ev if e == "agent_reply"), SNAPSHOT),
                  "calendar") <= TARGETS[ev[0][2]][0]
          for tid, ev in tickets.items() if tid not in not_due)
print(f"Attainment, every target on a calendar clock  : {cal}/{n}")

print("\nResolution clocks for solved tickets (calendar minutes)")
for tid, ev in sorted(tickets.items()):
    if ev[-1][1] != "solved":
        continue
    waiting, wait, last = True, 0, ev[0][0]
    for t, e, _ in ev:
        if waiting:
            wait += (t - last).total_seconds() / 60
        if e == "pending":
            waiting = False
        elif e == "customer_reply":
            waiting = True
        last = t
    total = (ev[-1][0] - ev[0][0]).total_seconds() / 60
    if total != wait:
        print(f"{tid}: total resolution {int(total)}, requester wait {int(wait)}")
```

3. Run `python3 sla.py`.

**Expected output.**

```text
ticket prio    clock     target  agent-FRT  result   autoreply-counts
T1     urgent  calendar      60         40  met      met
T2     urgent  calendar      60        100  BREACH   met
T3     normal  business     480        120  met      met
T4     normal  business     480        330  met      met
T5     normal  business     480         20  met      met
T6     high    business     240        270  BREACH   met
T7     low     business     960        120  met      met
T8     normal  business     480        490  BREACH*  met

Not yet due (running), left out of every rate : 0
Attainment, agent reply, open breaches counted: 5/8
Attainment, replied tickets only              : 5/7
Attainment, autoreply counts as a reply       : 8/8
Attainment, every target on a calendar clock  : 3/8

Resolution clocks for solved tickets (calendar minutes)
T1: total resolution 200, requester wait 60
T4: total resolution 1500, requester wait 360
```

**Validation.** Check three tickets by hand. T3 was created on Friday 9 October at 16:00 and answered on Monday at 10:00: one
business hour on Friday plus one on Monday is 120 minutes, although 66 calendar hours passed. T6 waited 4.5 business hours against a
4-hour target: a breach, which the autoreply hides. T8 has no human reply at the Friday 17:00 snapshot; 490 business minutes have
already passed, so it is a breach now (`BREACH*`), and a report that only counts replied tickets (5/7) hides it. T1's requester wait
time is 40 minutes before Pending plus 20 after the customer's reply: 60 of 200 calendar minutes.

**What to notice.** The same eight tickets give 5/8, 5/7, 8/8 or 3/8 depending on four definitional choices. Agree the definition
before the target. An unanswered ticket still inside its target is `running`: not yet due, so the script leaves it out of every
rate, as the metric dictionary's `tickets_due_in_period` does (the synthetic data has none; add one to see it).

**Troubleshooting.** `ValueError: time data ... does not match format`: a timestamp is not `YYYY-MM-DD HH:MM`. `KeyError` on a
priority: add it to `TARGETS`. Holidays are not modelled; real business-hour clocks need a holiday calendar and the customer's or
team's time zone.

**Teardown.** `rm -rf ~/supportops-labs/lab1`

#### Lab 2 (intermediate): Erlang C staffing, shrinkage and pooling

**Objective.** Turn a forecast into agents for an 80/20 service level, then test shrinkage, pooling, handle-time and volume
sensitivity and scale. **Prerequisites.** Python 3.8+. **Time.** 20 minutes. **Risk.** None.

1. Create the folder: `mkdir -p ~/supportops-labs/lab2 && cd ~/supportops-labs/lab2`.

2. Save the script as `erlang.py`.

_Example status: verified by execution on 2026-10-23 (Python 3.8.10, standard library)._

```python
"""Erlang C staffing for one queue of live contacts (standard library only)."""
import math


def erlang_c(n, a):
    """Probability that an arriving contact has to wait: n agents, a erlangs."""
    if n <= a:
        return 1.0
    b = 1.0                      # Erlang B, built up with the stable recursion
    for k in range(1, n + 1):
        b = a * b / (k + a * b)
    return n * b / (n - a * (1 - b))


def service_level(n, a, aht, t):
    """Share of contacts answered within t (t and aht in the same unit)."""
    if n <= a:
        return 0.0
    return 1 - erlang_c(n, a) * math.exp(-(n - a) * t / aht)


def asa(n, a, aht):
    """Average speed of answer (mean wait, all contacts)."""
    return erlang_c(n, a) * aht / (n - a) if n > a else float("inf")


def agents_needed(a, aht, t, target):
    n = math.floor(a) + 1
    while service_level(n, a, aht, t) < target:
        n += 1
    return n


VOLUME, INTERVAL_MIN = 100, 15     # contacts forecast for one 15-minute interval
AHT_MIN, T_MIN = 3.5, 20 / 60      # handle time 3:30; answer target 20 seconds
TARGET, SHRINKAGE = 0.80, 0.35     # 80/20 service level; 35% shrinkage

a = VOLUME / INTERVAL_MIN * AHT_MIN
print(f"Offered load: {a:.2f} erlangs")
print(" agents  P(wait)  SL(20s)  ASA(s)  occupancy")
for n in range(24, 31):
    print(f"{n:6d}  {erlang_c(n, a):7.1%}  {service_level(n, a, AHT_MIN, T_MIN):7.1%}"
          f"  {asa(n, a, AHT_MIN) * 60:6.1f}  {a / n:9.1%}")

n = agents_needed(a, AHT_MIN, T_MIN, TARGET)
print(f"Agents on the phones for 80/20: {n}")
scheduled = math.ceil(n / (1 - SHRINKAGE))
print(f"Agents to schedule at {SHRINKAGE:.0%} shrinkage: {scheduled}")

half = a / 2
split = 2 * agents_needed(half, AHT_MIN, T_MIN, TARGET)
print(f"Pooling: two separate queues of 50 need {split}; one pooled queue needs {n}")

a_slow = a * 1.10
print(f"AHT +10% (3:51): {agents_needed(a_slow, AHT_MIN * 1.10, T_MIN, TARGET)} agents")
a_peak = a * 1.20
peak = agents_needed(a_peak, AHT_MIN, T_MIN, TARGET)
print(f"Volume +20% (120 contacts): {peak} agents")

print("Scale (80/20, AHT 3:30): contacts per 15 min -> agents, occupancy")
for volume in (25, 50, 100, 200, 400, 1000):
    load = volume / INTERVAL_MIN * AHT_MIN
    need = agents_needed(load, AHT_MIN, T_MIN, TARGET)
    print(f"  {volume:5d} -> {need:4d} agents, occupancy {load / need:.1%}")
```

3. Run `python3 erlang.py`.

**Expected output.**

```text
Offered load: 23.33 erlangs
 agents  P(wait)  SL(20s)  ASA(s)  occupancy
    24    84.6%    20.6%   266.4      97.2%
    25    64.9%    44.6%    81.8      93.3%
    26    49.0%    62.0%    38.6      89.7%
    27    36.4%    74.4%    20.8      86.4%
    28    26.5%    83.0%    11.9      83.3%
    29    18.9%    89.0%     7.0      80.5%
    30    13.2%    93.0%     4.2      77.8%
Agents on the phones for 80/20: 28
Agents to schedule at 35% shrinkage: 44
Pooling: two separate queues of 50 need 30; one pooled queue needs 28
AHT +10% (3:51): 31 agents
Volume +20% (120 contacts): 33 agents
Scale (80/20, AHT 3:30): contacts per 15 min -> agents, occupancy
     25 ->    9 agents, occupancy 64.8%
     50 ->   15 agents, occupancy 77.8%
    100 ->   28 agents, occupancy 83.3%
    200 ->   53 agents, occupancy 88.1%
    400 ->  101 agents, occupancy 92.4%
   1000 ->  243 agents, occupancy 96.0%
```

**Validation.** The load is 100 ÷ 15 × 3.5 = 23.33 erlangs. Koole's handbook reports for the same inputs "only around 21%"
answered within 20 seconds at 24 agents and 28 agents for 80%;[^koole] the script gives 20.6% and 28. Schedule check: 28 ÷ (1 −
0.35) = 43.08, rounded up to 44.

**Troubleshooting.** `ZeroDivisionError` or an endless loop: the number of agents must exceed the load; the function starts above
it. For multi-skill queues, chats handled concurrently or strong abandonment, Erlang C is the wrong model (Lab 4).

**Teardown.** `rm -rf ~/supportops-labs/lab2`

#### Lab 3 (intermediate): claimed versus verified resolution, re-contact and CSAT

**Objective.** From a ticket export, compare an AI agent's vendor-style resolution rate with resolutions that held for seven days,
and compute one-touch resolution, reopen and re-contact rates, CSAT with its uncertainty, and backlog age. **Prerequisites.**
bash and Python 3.8+. **Time.** 30 minutes. **Risk.** None.

1. Create the folder and the data.

_Example status: verified by execution on 2026-10-23 (bash, Linux)._

```bash
mkdir -p ~/supportops-labs/lab3 && cd ~/supportops-labs/lab3
cat > tickets.csv <<'CSV'
id,customer,topic,channel,handler,bot_outcome,created,solved,replies,reopened,csat
1,C01,login,chat,bot,assumed,2026-09-01,2026-09-01,0,0,
2,C01,login,email,agent,,2026-09-02,2026-09-02,1,0,good
3,C02,billing,email,agent,,2026-09-01,2026-09-03,2,0,good
4,C03,export,chat,bot,confirmed,2026-09-02,2026-09-02,0,0,
5,C04,api,email,agent,,2026-09-02,2026-09-05,3,1,bad
6,C05,login,chat,bot,assumed,2026-09-03,2026-09-03,0,0,
7,C06,billing,chat,bot,assumed,2026-09-03,2026-09-03,0,0,
8,C06,billing,phone,agent,,2026-09-04,2026-09-04,1,0,bad
9,C07,export,email,agent,,2026-09-04,2026-09-04,1,0,good
10,C08,api,email,agent,,2026-09-07,2026-09-09,2,0,
11,C09,login,chat,bot,escalated,2026-09-07,2026-09-07,0,0,
12,C09,login,chat,agent,,2026-09-07,2026-09-07,1,0,good
13,C10,billing,email,agent,,2026-09-08,2026-09-08,1,1,
14,C11,export,chat,bot,assumed,2026-09-08,2026-09-08,0,0,
15,C12,api,chat,bot,confirmed,2026-09-09,2026-09-09,0,0,
16,C12,api,email,agent,,2026-09-20,2026-09-21,1,0,good
17,C13,login,email,agent,,2026-09-10,2026-09-10,1,0,good
18,C05,login,email,agent,,2026-09-08,2026-09-08,2,0,bad
19,C14,billing,email,agent,,2026-09-11,,1,0,
20,C02,export,email,agent,,2026-09-14,,2,0,
21,C03,api,phone,agent,,2026-09-21,,0,0,
22,C07,login,chat,bot,assumed,2026-09-22,2026-09-22,0,0,
23,C04,billing,email,agent,,2026-09-24,2026-09-25,1,0,good
24,C11,export,email,agent,,2026-09-25,2026-09-25,1,0,
25,C13,login,email,agent,,2026-09-15,2026-09-15,1,0,good
CSV
```

2. Save the script as `metrics.py`.

_Example status: verified by execution on 2026-10-23 (Python 3.8.10, standard library)._

```python
"""Support metrics from a ticket export: what the headline numbers hide."""
import csv
import math
from datetime import date

SNAPSHOT = date(2026, 9, 30)
WINDOW = 7   # days: a new contact on the same topic within this window = re-contact

with open("tickets.csv", newline="") as f:
    rows = list(csv.DictReader(f))
for r in rows:
    r["created"] = date.fromisoformat(r["created"])
    r["solved"] = date.fromisoformat(r["solved"]) if r["solved"] else None


def recontacted(r):
    """Same customer, same topic, new contact within WINDOW days after this one ended."""
    end = r["solved"] or r["created"]
    later = lambda o: (o["created"], int(o["id"])) > (r["created"], int(r["id"]))
    return any(later(o) and o["customer"] == r["customer"] and o["topic"] == r["topic"]
               and 0 <= (o["created"] - end).days <= WINDOW for o in rows)


def wilson(k, n, z=1.96):
    if n == 0:
        return (0.0, 0.0)
    p = k / n
    centre = (p + z * z / (2 * n)) / (1 + z * z / n)
    half = z * math.sqrt(p * (1 - p) / n + z * z / (4 * n * n)) / (1 + z * z / n)
    return centre - half, centre + half


def pct(k, n):
    return f"{k}/{n} = {100 * k / n:.1f}%" if n else "n/a"


bot = [r for r in rows if r["handler"] == "bot"]
claimed = [r for r in bot if r["bot_outcome"] in ("confirmed", "assumed")]
held = [r for r in claimed if not recontacted(r)]
print("AI agent")
print(f"  {'Vendor-style resolution rate':29}: {pct(len(claimed), len(bot))}")
print(f"  {f'No re-contact within {WINDOW} days':29}: {pct(len(held), len(bot))}")
back = [r["id"] for r in claimed if recontacted(r)]
print(f"  {'Re-contacted resolutions':29}: {back}")

agent = [r for r in rows if r["handler"] == "agent"]
solved = [r for r in agent if r["solved"]]
one_touch = [r for r in solved if r["replies"] == "1" and r["reopened"] == "0"]
reopened = [r for r in solved if r["reopened"] == "1"]
recon = [r for r in solved if recontacted(r)]
print("Human-handled tickets")
print(f"  {'One-touch resolution':29}: {pct(len(one_touch), len(solved))}")
print(f"  {'Reopened':29}: {pct(len(reopened), len(solved))}")
print(f"  {f'Re-contact within {WINDOW} days':29}: {pct(len(recon), len(solved))}")

rated = [r for r in solved if r["csat"]]
good = sum(r["csat"] == "good" for r in rated)
lo, hi = wilson(good, len(rated))
print(f"  {'CSAT (good / rated)':29}: {pct(good, len(rated))}, "
      f"95% interval {100 * lo:.1f}%-{100 * hi:.1f}%")
print(f"  {'Survey response rate':29}: {pct(len(rated), len(solved))}")

backlog = [r for r in agent if not r["solved"]]
buckets = {"0-7 days": 0, "8-14 days": 0, "15+ days": 0}
for r in backlog:
    age = (SNAPSHOT - r["created"]).days
    key = "0-7 days" if age <= 7 else "8-14 days" if age <= 14 else "15+ days"
    buckets[key] += 1
print(f"Backlog on {SNAPSHOT}: {len(backlog)} open, by age {buckets}")
```

3. Run `python3 metrics.py`.

**Expected output.**

```text
AI agent
  Vendor-style resolution rate : 7/8 = 87.5%
  No re-contact within 7 days  : 4/8 = 50.0%
  Re-contacted resolutions     : ['1', '6', '7']
Human-handled tickets
  One-touch resolution         : 9/14 = 64.3%
  Reopened                     : 2/14 = 14.3%
  Re-contact within 7 days     : 1/14 = 7.1%
  CSAT (good / rated)          : 8/11 = 72.7%, 95% interval 43.4%-90.3%
  Survey response rate         : 11/14 = 78.6%
Backlog on 2026-09-30: 3 open, by age {'0-7 days': 0, '8-14 days': 1, '15+ days': 2}
```

**Validation.** By hand: bot conversations 1, 6 and 7 were counted as resolved (all three as assumed resolutions) but the same
customers came back on the same topic one, five and one days later on another channel (tickets 2, 18 and 8). Conversation 15's
customer came back after 11 days, outside the window. On the human side, ticket 17's customer came back five days later (ticket
25). Eleven of fourteen solved tickets were rated, eight good: 72.7%, but with only eleven ratings the 95% Wilson interval (a range for a proportion that
stays sensible at small n) runs from 43% to 90%, so a week-on-week change of ten points means nothing at this volume.

**What to notice.** An "assumed resolution" (the customer left without asking for more help) is not evidence that the problem
was solved.[^fin-outcomes] Measure every automated channel with the same re-contact rule.

**Troubleshooting.** Real exports need timestamps, not dates, to order same-day contacts (the script breaks ties by ticket id), and
a stable customer key across channels; without one, re-contact is under-counted.

**Teardown.** `rm -rf ~/supportops-labs/lab3`

#### Lab 4 (advanced): test Erlang C against a simulation with abandonment

**Objective.** Simulate the Lab 2 queue call by call, confirm that the simulation matches Erlang C when nobody hangs up, then add
impatient callers and see how far the model's answer moves. **Prerequisites.** Lab 2. **Time.** 30 minutes. **Risk.** None (runs in
about a second).

1. Create the folder: `mkdir -p ~/supportops-labs/lab4 && cd ~/supportops-labs/lab4`.

2. Save the script as `simulate.py`.

_Example status: verified by execution on 2026-10-23 (Python 3.8.10, standard library)._

```python
"""Check the Erlang C answer by simulation, with and without callers who hang up."""
import heapq
import math
import random

RATE = 100 / 15        # arrivals per minute (100 per 15 minutes)
AHT = 3.5              # mean handle time, minutes
T = 20 / 60            # answer target: 20 seconds
CALLS = 200_000


def erlang_c_sl(n, a):
    b = 1.0
    for k in range(1, n + 1):
        b = a * b / (k + a * b)
    c = n * b / (n - a * (1 - b))
    return 1 - c * math.exp(-(n - a) * T / AHT)


def simulate(agents, mean_patience, seed=7):
    """First-come-first-served queue; a caller whose wait exceeds patience hangs up."""
    rng = random.Random(seed)
    free = [0.0] * agents            # time at which each agent becomes free
    clock = 0.0
    answered = answered_in_t = abandoned = abandoned_after_t = 0
    wait_sum = 0.0
    for _ in range(CALLS):
        clock += rng.expovariate(RATE)
        patience = rng.expovariate(1 / mean_patience) if mean_patience else math.inf
        service = rng.expovariate(1 / AHT)
        wait = max(0.0, free[0] - clock)
        if wait > patience:
            abandoned += 1
            abandoned_after_t += patience > T
            continue
        start = clock + wait
        heapq.heapreplace(free, start + service)
        answered += 1
        answered_in_t += wait <= T
        wait_sum += wait
    sl2 = answered_in_t / (answered + abandoned_after_t)    # Koole's SL2 definition
    return sl2, abandoned / CALLS, 60 * wait_sum / answered


a = RATE * AHT
print("agents  patience   SL(20s)  abandoned  ASA(s)  Erlang C SL")
for agents in (26, 28):
    for patience in (None, 3.0, 1.0):
        sl, ab, asa = simulate(agents, patience)
        label = "infinite" if patience is None else f"{patience:.0f} min"
        print(f"{agents:6d}  {label:8}  {sl:7.1%}  {ab:9.1%}  {asa:6.1f}  "
              f"{erlang_c_sl(agents, a):10.1%}")
```

3. Run `python3 simulate.py`.

**Expected output.**

```text
agents  patience   SL(20s)  abandoned  ASA(s)  Erlang C SL
    26  infinite    62.6%       0.0%    41.0       62.0%
    26  3 min       85.0%       4.2%     6.9       62.0%
    26  1 min       93.3%       5.8%     2.9       62.0%
    28  infinite    83.4%       0.0%    11.5       83.0%
    28  3 min       92.0%       2.2%     3.6       83.0%
    28  1 min       96.5%       3.3%     1.6       83.0%
```

**Validation.** With infinite patience the simulated service level is within one point of Erlang C (62.6% vs 62.0%, 83.4% vs
83.0%); that confirms the simulation. The fixed seed makes the output repeatable on the same Python version; other versions may
differ in the last digit.

**What to notice.** With a three-minute mean patience, 26 agents reach 85% in 20 seconds, because 4.2% of callers hang up and
stop loading the queue. That is the over-staffing Erlang C can produce when callers abandon,[^aam07][^koole] and also a warning:
the "better" service level is bought with hang-ups, many of whom call back (redials are not simulated here).

**Troubleshooting.** Slow on very old hardware: reduce `CALLS` to 50,000 (results move by a few tenths of a point). To model time-
varying arrivals, simulate each 15-minute interval with its own rate and carry the queue over.

**Teardown.** `rm -rf ~/supportops-labs`

### Use cases and scenarios

Three documented cases and two illustrative scenarios. The documented cases are described only as far as their public sources
go.

#### Use case 1: support operations as a systems team at GitLab (documented)

**Context.** In GitLab's public handbook, Support is accounted for as Cost of Sales; support engineers are "not commissioned or bonused" for upsell; KPIs are reviewed weekly in a "Support
Week-in-Review".[^gl-support] The handbook's naming guide shows a "Support Operations" unit inside "Support Readiness", and the team
that owns the tooling now appears as "Customer Support Systems".[^gl-support][^gl-css]

**Method.** The systems team states its purpose (knowledge, tools and data for the support team), accepts changes only through
templates filed by specific roles ("issues filed outside the appropriate role will be closed"), publishes a triage → plan or
develop → validate → implement flow, and keeps pages on audits and change management.[^gl-css] It also publishes the definitions it
uses for each Zendesk clock.[^gl-metrics]

**Trade-offs.** Restricting who can request changes slows small fixes but stops the helpdesk becoming a pile of one-off rules.

**What to copy.** A written purpose, a single intake for helpdesk changes, validation before release, and a public metric
dictionary. **What not to infer.** Nothing on the public pages shows GitLab's SLA attainment or staffing; do not quote this case
as evidence of results.

#### Use case 2: an AI assistant at Klarna, and the human channel (documented, company claims)

**Context.** Klarna said in February 2024 that its AI assistant had "2.3 million conversations, two-thirds of Klarna's customer
service chats" in its first month, doing "the equivalent work of 700 full-time agents", with customer satisfaction "on par with
human agents", "a 25% drop in repeat inquiries" and resolution in under 2 minutes instead of 11; it estimated a $40 million profit
improvement for 2024.[^klarna-2024] In May 2025 its CEO told Bloomberg, as reported by Entrepreneur, "I just think it's so critical
that you are clear to your customer that there will always be a human if you want", and Klarna was recruiting human customer
service staff again.[^klarna-2025]

**Trade-offs and lessons.** The 2024 figures are self-reported and the public sources do not say how "resolution" or "repeat
inquiry" was measured. The 2025 statement moves the question from replacement to **access**: how reliably a customer reaches a
person. Transferable practice: report AI performance by re-contact and hand-off quality, keep the human path visible, and plan
staffing for the possibility that the contacts AI leaves behind are harder and longer, which would raise AHT for the human queue
(an expectation to measure, not a sourced finding).

#### Use case 3: accountability for chatbot answers at Air Canada (documented, legal decision)

**Context.** In *Moffatt v. Air Canada* (2024 BCCRT 149, 14 February 2024), a customer relied on the airline's website chatbot,
which wrongly suggested that a bereavement fare could be claimed retroactively. The British Columbia Civil Resolution Tribunal found
the airline liable for negligent misrepresentation. It rejected the argument that the chatbot was responsible for its own actions:
the chatbot "is still just a part of Air Canada's website", and "It should be obvious to Air Canada that it is responsible for all
the information on its website"; it found that "Air Canada did not take reasonable care to ensure its chatbot was
accurate".[^aircanada]

**Lesson for SupportOps.** Treat policy answers from automation as official statements: restrict AI agents to approved, current
sources for refunds, prices and rights; route such topics to humans or to deterministic flows; keep transcripts; review a sample
in QA. This is a single small-claims decision in one Canadian province; it is persuasive as an example, not binding law elsewhere.

#### Scenario 4: a launch week that nearly doubles chat volume (illustrative)

::: example Illustrative scenario: forecasting and staffing a launch
A software company will email 200,000 customers about a pricing change on a Tuesday. A comparable change last year raised chat
volume by about 80% for three days. Forecasting per 15-minute interval with Lab 2's model gives peaks needing 48 agents against 28. Options: borrow trained staff from other teams for three
days, extend hours, stagger the email in four waves, and publish a targeted FAQ linked from the email. The team chooses staggered
waves plus the FAQ (lower peak) and four borrowed agents. Success criteria are written in advance: 80/20 met in at least 90% of
intervals, abandonment under 5%, re-contact on "pricing" under the normal rate within a week. The post-launch review compares
forecast with actuals per interval and adds the event to the calendar.
:::

**Pitfall.** Planning the average day; the peak interval decides the service.

#### Scenario 5: plan-based SLAs and an OLA with engineering (illustrative)

::: example Illustrative scenario: from one SLA to tiers
A B2B SaaS company sells Standard and Enterprise plans. Enterprise contracts promise a one-hour first reply on urgent tickets, 24×7.
SupportOps adds entitlement lookup at intake, two SLA policies (Enterprise first), an out-of-hours on-call rotation, and an OLA
with engineering: acknowledge escalated urgent defects within 30 minutes, update every 4 hours. The monthly service review shows that 70% of urgent breaches happen while waiting for engineering, not
in support; the OLA, not more support staff, becomes the fix.
:::

**Pitfall.** Selling an SLA before the clock, the on-call rota and the OLA exist; the first breach is then a contract issue.

## Measure, govern, pay

### Metrics and KPIs

Measure the queue, the clock and the loop. Each KPI below has a formula; definitions live in the metric dictionary (Artefact 2).

| KPI | Definition / formula | Leading or lagging | Pitfall | Review |
|---|---|---|---|---|
| SLA attainment by priority | Tickets meeting target ÷ tickets due, open breaches included | Lagging | Autoreplies, Pending parking, excluding open tickets | Daily, weekly |
| Requester wait time (p50, p80) | Time in New, Open, On-hold until solved | Lagging | Averages hide the long tail; use percentiles | Weekly |
| Backlog by age | Open tickets per age bucket | Leading | A flat count can hide an ageing tail | Daily |
| Live service level and abandonment | SL2 at target seconds; abandoned ÷ offered | Lagging (per interval) | Definition choice (SL1 rewards hang-ups) | Intraday, weekly |
| Re-contact within 7 days | Same customer and reason within 7 days ÷ solved | Lagging | Needs a customer key across channels | Weekly |
| One-touch resolution | Solved with one agent reply and not reopened ÷ solved | Lagging | Rewards premature closing if used alone | Monthly |
| Transactional CSAT | Good ÷ all ratings, with n, response rate and interval | Lagging | Small samples; survivorship; survey design is [CXOps](../cxops/) | Monthly |
| Forecast error | Mean absolute percentage error per interval and day; bias | Leading | Daily accuracy hides interval misses | Weekly |
| Occupancy and shrinkage | As defined in [Capacity](#shrinkage-occupancy-and-schedules) | Leading | Targeting occupancy degrades service | Weekly |
| Escalation acceptance and age | Escalations accepted as valid ÷ sent; age vs OLA | Leading | Engineering may close quietly | Monthly |
| Verified automation resolution | Bot or self-service sessions with no re-contact ÷ sessions | Lagging | Vendor "assumed" outcomes | Weekly |
| Cost per resolved contact, by channel | Total cost ÷ contacts resolved without re-contact | Lagging | Allocation choices; never an agent target | Quarterly |

**Vanity traps.** Tickets closed per agent; average handle time as an individual target (rewards rushing and transfers);
deflection without re-contact; CSAT without the number of ratings.

#### A worked calculation

::: example Illustrative scenario: one month's scorecard
A team received 6,000 email tickets in a month; 5,400 were due for a first reply in the month. 4,700 got a human first reply within
target, 380 got one late, and 320 were still unanswered past target at month end. Attainment = 4,700 ÷ 5,400 = **87.0%**. Counting
only replied tickets gives 4,700 ÷ 5,080 = 92.5%, which hides 320 customers still waiting.
Of 5,600 tickets solved, 610 were followed by a contact from the same customer on the same reason within seven days: re-contact =
610 ÷ 5,600 = **10.9%**. The AI agent claimed 2,000 resolutions; 520 of those customers came back within seven days, so verified
automation resolutions = 1,480 and the verified rate is 1,480 ÷ 2,000 = **74%** of claimed. With total monthly cost of 210,000 (in
any currency) and 5,600 − 610 + 1,480 = 6,470 contacts resolved without re-contact, cost per resolved contact = 210,000 ÷ 6,470 ≈
**32.5**.
:::

### Quality, security, privacy and compliance

- **Personal data in tickets.** Tickets collect names, emails, screenshots and logs, and often more than needed. In the EU/EEA,
  GDPR's storage-limitation principle requires personal data to be kept "for no longer than is necessary for the purposes for
  which the personal data are processed".[^gdpr5] Set a retention period per ticket type, automate deletion or redaction, and
  include attachments and exports in the scope. Wider programme design is on [PrivacyOps](../privacyops/).
- **Payment card data.** Do not collect full card numbers in tickets. Zendesk documents a credit-card field (Enterprise plans, as of
  October 2026) that stores only the last four digits, states that PCI allows storing the first six and last four, and warns that following its recommendations
  "won't make your Zendesk PCI-compliant".[^zd-cc] Route payment changes to the payment system, not the ticket.
- **Least privilege.** Contractors and outsourced agents see only their brands, groups and fields; administrators are few; API
  tokens are scoped and rotated; integrations are reviewed when staff leave.
- **Audit trail.** Keep the ticket event history and the helpdesk change log; both are evidence in disputes and in audits against
  [ComplianceOps](../complianceops/)-style controls or ISO 18295 certification.[^iso18295-1]
- **AI agents.** Disclosure, approved sources and human hand-off, as in [Automation and AI](#automation-and-ai).
- **Regulated sectors** (health, finance, government) add complaint-handling rules, call-recording consent and data residency;
  check them per jurisdiction.

### Cost, capacity and sustainability

People are most of the cost, so the levers are: fewer contacts (fix causes, better self-service), shorter but complete handling
(knowledge, tools), less waste (pooling, accurate forecasts, schedules that fit demand) and the right channel for each problem; a
self-service attempt that ends in a live contact costs more than either alone. Outcome-priced AI agents add a variable
cost tied to the vendor's definition of an outcome; reconcile it monthly against verified resolutions.[^fin-outcomes]
**Human sustainability** is the binding constraint: occupancy targets near 100%,
or schedules without coaching time, raise attrition, and new agents have higher AHT, which raises the staffing need again.[^koole]
Environmental impact is usually small; where it matters, see [GreenOps](../greenops/).

### Assurance of the operating model

| Check | Frequency | Signal of trouble |
|---|---|---|
| Re-time 20 random tickets by hand against the SLA definition | Quarterly | Tool and definition disagree |
| Pending and On-hold use per agent | Weekly | Parking tickets to stop clocks |
| Rules audit: triggers, automations, macros without owner or use | Quarterly | Unknown rules, conflicting priorities |
| Forecast error and bias by interval | Weekly | Repeated misses on the same weekday or event |
| QA calibration spread between reviewers | Monthly | Scores depend on the reviewer |
| AI transcript sample against approved sources | Weekly | Answers outside policy or from stale articles |
| Escalations past OLA | Weekly | Engineering interface broken |

## When things go wrong

### Common failures and troubleshooting

| Symptom | Likely cause | Diagnosis | Remediation | Prevention |
|---|---|---|---|---|
| SLA attainment high, customers angry | Clock stops on autoreply or Pending; open breaches excluded | Re-time a sample (Lab 1) | Fix definitions; report open breaches | Written clock definitions |
| Backlog grows every Monday | Weekend arrivals, weekday staffing | Arrivals and capacity by hour | Weekend or early-Monday cover; stagger | Forecast per interval |
| Hard tickets age, easy ones fly | Cherry-picking, oldest-first not enforced | Age of oldest ticket per queue | Assignment by routing, not choice | Queue order by SLA breach |
| Re-contact rises after a bot launch | Assumed resolutions, poor hand-off | Lab 3 on bot sessions | Hand-off rules; restrict topics | Measure verified resolution |
| Same bug, hundreds of tickets, no fix | No problem linking, no escalation owner | Tickets per defect | Problem ticket, engineering link, status message | Monthly top-problems review |
| Agents leaving, AHT rising | Occupancy too high, no coaching time | Occupancy and shrinkage trend | Add capacity; protect coaching | Occupancy cap in planning |

### Worked runbook: a backlog surge after a release

::: figure Runbook: from a backlog alert to recovery and prevention
```mermaid
flowchart TB
  A["Alert: backlog over threshold or SLA breaches rising"]
  B{"One main cause?"}
  C["Declare mass issue: problem ticket, link incidents"]
  D["Status message and macro, engineering link"]
  E["Capacity response: overtime, borrow staff, pause low priority"]
  F["Recovery plan: clear by age and priority, daily burn-down"]
  G["Review: forecast, release calendar, escalation timing"]
  A --> B
  B -->|yes| C
  C --> D
  D --> F
  B -->|no| E
  E --> F
  F --> G
  classDef risk fill:#fbeceb,stroke:#b4332b,color:#122029
  classDef decision fill:#fdf3e3,stroke:#c9800f,color:#122029
  classDef core fill:#e8f3f2,stroke:#16756f,color:#122029
  class A risk
  class B decision
  class C,D,E,F,G core
```
Text equivalent: an alert fires when the backlog passes a threshold or SLA breaches rise. The first decision is whether one cause
is behind most new tickets. If yes, declare a mass issue: create a problem ticket, link the incident tickets, publish a status
message and macro, and link the engineering issue. If no, respond with capacity: overtime, borrowed staff, pausing low-priority
work. Both paths lead to a recovery plan that clears tickets by age and priority with a daily burn-down, and then to a review of
the forecast, the release calendar and escalation timing.
:::

::: example Illustrative scenario: release 4.2 breaks single sign-on for some customers
**09:40 Tuesday.** Backlog alert: 380 open tickets against a normal 150. **Diagnose (15 min).** 70% of new tickets mention login
after the 08:00 release. **Mass issue (30 min).** A problem
ticket is created; agents link incoming login tickets to it with a macro that explains the issue and promises an update by 13:00;
the status page is updated via the [IncidentOps](../incidentops/) liaison; the engineering incident is linked. **Capacity (1 h).**
Low-priority queues are paused; two L2 specialists move to the login queue to handle edge cases. **Fix (14:10).** Engineering
rolls back; solving the problem ticket solves 260 linked tickets with one tested message.[^zd-prob] **Recovery (2 days).**
Backlog cleared oldest first. **Review (Friday).** The release calendar was not
shared with WFM; release notes now go to support 48 hours before deployment, and SSO changes get a canary to a small customer set
first. Success is measured as backlog back under 150 within two business days and no rise in seven-day re-contact on "login".
:::

### Anti-patterns and myths

- **"Average handle time is the productivity metric."** As an individual target it produces rushed answers, transfers and repeat
  contacts, and low FCR even raises occupancy (see [Capacity](#capacity-the-queueing-maths-behind-every-sla)).[^koole]
- **"Deflection is savings."** Only verified deflection is; the rest is moved or delayed work.
- **"AI will replace the team."** The evidence supports assistance and partial automation with a human path; assistance even
  lowered quality slightly for the most experienced agents in the one large study.[^blr][^klarna-2025]
- **"Support should not bother engineering."** Then engineering hears about defects from churn. Design the interface instead.

## Deciding and adopting

### When to use and when not to use

**Invest in a SupportOps role or team when** several of these hold: more than about ten people answer customers, or more than one
channel or time zone; SLAs are sold in contracts; headcount requests cannot be answered from data; the helpdesk has rules nobody
can explain; engineering complains about escalation quality or support complains about engineering silence. These thresholds are
this Atlas's judgement, not a researched cut-off.

**Do not build a separate team when** volume is low and one person can answer and administer; when the product is changing so
fast that the real fix is in the product, not the queue; or when support is a short-lived launch function. Give one person the
SupportOps hat for a few hours a week instead, using this page's checklists.

### Decision framework

::: figure Decision tree: how much SupportOps, and tiers or swarming
```mermaid
flowchart TB
  Q1{"10+ people or several channels?"}
  Q2{"Contract SLAs or growing backlog?"}
  P["Part-time owner"]
  T["Dedicated SupportOps team"]
  Q3{"95%+ known, solved on first contact?"}
  TI["Tiers plus escalation template"]
  SW["Swarming or hybrid"]
  Q1 -->|no| P
  Q1 -->|yes| Q2
  Q2 -->|no| P
  Q2 -->|yes| T
  T --> Q3
  Q3 -->|yes| TI
  Q3 -->|no| SW
  classDef decision fill:#fdf3e3,stroke:#c9800f,color:#122029
  classDef core fill:#e8f3f2,stroke:#16756f,color:#122029
  class Q1,Q2,Q3 decision
  class P,T,TI,SW core
```
Text equivalent: if fewer than about ten people answer customers on few channels, a part-time owner of clocks, taxonomy and
checklists is enough. If the team is larger, the next question is whether SLAs are in contracts or the backlog keeps growing; if
not, a part-time owner still suffices; if so, build a dedicated SupportOps function covering workforce management, routing, data
and change control. That function then chooses a tiered model with a clear escalation template when 95% or more of issues are known
and resolved on the first contact (the Consortium for Service Innovation's condition for tiers), or swarming or a hybrid for new and complex issues.
:::

For choosing tools or an operating model, a weighted comparison keeps the argument honest. Weights are this Atlas's illustration;
set your own before scoring.

| Criterion | Weight | Helpdesk-native only | Helpdesk + WFM suite | Helpdesk + WFM + outsourced L1 |
|---|---|---|---|---|
| Fits volume and channels | 0.25 | 3 | 5 | 5 |
| Clock and routing control | 0.20 | 4 | 5 | 4 |
| Total cost | 0.20 | 5 | 3 | 3 |
| Speed to change | 0.15 | 5 | 4 | 2 |
| Quality control | 0.20 | 4 | 4 | 3 |
| **Weighted score** | 1.00 | **4.10** | **4.25** | **3.55** |

_Scores 1–5 for an illustrative company with three channels and about 40 agents; with 10 agents the first option wins on cost and
speed._

### Maturity model

This is **this Atlas's model**, not an industry standard.

::: figure Maturity levels of a support operation
```mermaid
flowchart TB
  L1["1 Reactive: shared inbox, no clocks"]
  L2["2 Defined: helpdesk, written SLA clocks, taxonomy"]
  L3["3 Managed: forecasts, staffing model, QA, metric dictionary"]
  L4["4 Integrated: escalation OLAs, problem loop, verified automation"]
  L5["5 Adaptive: interval planning, experiments, causes removed"]
  L1 --> L2
  L2 --> L3
  L3 --> L4
  L4 --> L5
  classDef neutral fill:#f1f4f6,stroke:#5b7a87,color:#122029
  classDef core fill:#e8f3f2,stroke:#16756f,color:#122029
  class L1,L2 neutral
  class L3,L4,L5 core
```
Text equivalent: five levels in sequence. Level 1, reactive: a shared inbox and no clocks. Level 2, defined: a helpdesk, written SLA
clocks and a taxonomy. Level 3, managed: forecasts, a staffing model, QA and a metric dictionary. Level 4, integrated: escalation
OLAs with engineering, a problem loop and verified automation. Level 5, adaptive: interval-level planning, controlled experiments
and measurable removal of contact causes.
:::

| Level | Observable behaviour | Exit criterion to next level |
|---|---|---|
| 1 Reactive | Replies when someone notices; volume unknown | Every request is a ticket with a timestamp |
| 2 Defined | SLA targets exist; definitions written | Re-timed sample matches the tool; open breaches reported |
| 3 Managed | Staffing derived from forecast and model; QA calibrated | Forecast error tracked; occupancy and shrinkage measured |
| 4 Integrated | Engineering OLA; top-problems list acted on; AI measured by re-contact | Contact rate per customer falls for addressed reasons |
| 5 Adaptive | Changes tested (A/B or staged); routing and staffing tuned per interval | Sustained gains without rising re-contact or attrition |

### Adoption roadmap: 30/60/90 days

| Window | Actions | Milestones and metrics |
|---|---|---|
| Days 1–30 | Inventory channels, rules, macros and reports; write clock definitions; set priority automatically; start the daily queue stand-up; export event history | Metric dictionary v1; first honest SLA attainment with open breaches; backlog-by-age report |
| Days 31–60 | Contact-reason taxonomy; routing by skill and SLA order; escalation template and OLA draft; per-interval forecast for live channels; QA scorecard and first calibration | Re-route rate measured; staffing model for one channel; escalation acceptance rate baseline |
| Days 61–90 | Change control for the helpdesk; problem-linking SOP; verified-resolution measure for bots and self-service; monthly service review with engineering; top-five problems to product | Re-contact baseline; forecast error tracked; first cause removed and its contact rate measured |

Quick wins: autoreply no longer stops the SLA clock; oldest-ticket view per queue; one macro review pass; a visible "talk to a
person" path.

## Toolkit

### Checklists

**Quick start (first week)**

- [ ] Every channel creates a ticket with a timestamp and a customer key
- [ ] Priority is set automatically at creation
- [ ] Clock definitions written for each SLA metric
- [ ] Daily report shows open breaches and backlog by age

**Before launching an SLA tier**

- [ ] Entitlement lookup at intake
- [ ] Policy order tested with synthetic tickets
- [ ] Out-of-hours rota for calendar-hour targets
- [ ] OLA agreed with engineering for escalations
- [ ] Customer-facing wording matches the clock definition

**Weekly operations review**

- [ ] SLA attainment by priority (open breaches included)
- [ ] Re-contact within 7 days, by channel and for automation
- [ ] Forecast error and schedule adherence
- [ ] Top contact reasons and their trend
- [ ] Escalations past OLA

**Before launching an AI agent**

- [ ] Disclosed as AI; human reachable in one step
- [ ] Restricted topics routed to humans or fixed flows
- [ ] Approved, current sources only; owners for each source
- [ ] Re-contact measurement in place before launch
- [ ] Transcript sampling in QA and a rollback switch

### Templates

**Escalation to engineering** (paste into the issue tracker):

```text
Title: [Product area] short symptom (N customers, severity S)
Customer impact: who, how many, since when, business effect
Linked tickets: IDs (problem ticket if any)
Steps to reproduce: 1. ... 2. ... 3. ...
Expected vs actual:
Environment / version / region:
Logs and screenshots: attached, personal data removed
Workaround tried / given to customers:
Requested severity and reason (rubric v2):
Support owner: name, next customer update due at: time
```

**Helpdesk change request**:

```text
Change: what rule, macro, field, form or SLA changes
Reason and evidence: ticket IDs, metric, incident
Owner and approver:
Test: synthetic tickets used and results (sandbox)
Effect on clocks or routing: yes/no, details
Rollback: how, by whom
Release date and announcement to agents:
```

**QA scorecard** (weights are an example):

| Criterion | Weight | Pass looks like |
|---|---|---|
| Correct and complete resolution | 30 | Answer solves the stated problem; no follow-up needed |
| Policy and security | 20 | Identity checked where required; no sensitive data requested |
| Expectations set | 15 | Next step and time given when not solved |
| Clarity and tone | 15 | Plain language, customer's terms |
| Right escalation or link | 10 | Escalated with template, or linked to problem ticket |
| Correct fields and tags | 10 | Reason, product area and priority correct |

**SOP: mass issue handling** (one page): trigger (three or more tickets on one new symptom within an hour, or an engineering
incident); create the problem ticket; publish the agent macro and customer status; link the engineering issue; assign a support
liaison to [IncidentOps](../incidentops/); update customers at the promised time; solve via the problem ticket; review within five
business days.

### Deep comparisons

| Question | SupportOps | [CustomerOps](../customerops/) | [CXOps](../cxops/) | [ITOps](../itops/) |
|---|---|---|---|---|
| Trigger | Customer contacts you | Lifecycle event or risk signal | Feedback across the journey | Employee contacts IT |
| Unit of work | Ticket | Account | Insight and action | Incident, request |
| Core measure | SLA, re-contact, cost per resolution | Retention, expansion | Measured effect of fixes | SLA, change success |
| Core maths | Queueing, forecasting | Survival, cohorts | Survey statistics | Queueing (same as support) |

### FAQ

**Is SupportOps a job title?** Yes, mostly as "support operations" (manager, analyst, specialist). The one-word form is informal
shorthand.[^zd-blog][^gl-support]

**Do we need WFM software?** Not for one channel and a stable volume: a spreadsheet with Erlang C and a per-interval forecast is
enough. Multi-skill routing, many channels, labour-law constraints and hundreds of agents justify a WFM suite.

**What is a good first-reply target?** The one your customers value and you can staff. Industry figures vary by sector and are
rarely comparable because clocks differ; this page gives none for that reason.

**How do we count an AI agent's success?** Verified resolution: sessions with no contact on the same reason within a window,
plus hand-off quality. A vendor's billed "resolution" may include assumed outcomes.[^fin-outcomes]

**What if engineering will not sign an OLA?** Measure escalation age anyway and bring it to the monthly service review with the
breaches it causes; a contract SLA that depends on engineering is an executive decision, not a support one.

## Going further

### Advanced topics and emerging direction

- **Established:** multi-skill staffing and routing, Erlang A and simulation, time-varying staffing; see the operations research
  survey for entry points.[^aam07]
- **Active practice, evidence still thin:** AI agents with outcome-based pricing; AI drafting and summarisation for agents (one
  large field study in one firm);[^blr] automatic contact-reason classification; quality review of every conversation by models.
- **Regulatory direction:** AI transparency obligations (EU AI Act Article 50 from August 2026) and liability for automated
  answers.[^aiact50][^aircanada]
- **Marketing claims to test before believing:** "autonomous support", fixed percentage deflection promises, and benchmark CSAT
  figures without a stated survey method.

### Learning path

| Stage | Do this |
|---|---|
| 1-day primer | Read [The ticket lifecycle](#the-ticket-lifecycle) and [Capacity](#capacity-the-queueing-maths-behind-every-sla); run Labs 1 and 2 |
| 1 week | Write your team's clock definitions; re-time 20 tickets; build the backlog-by-age report |
| 30 days | Forecast one channel per interval for four weeks and track error; run Lab 3 on an anonymised export; draft the escalation template with engineering |
| Advanced | Simulation for multi-skill queues (Lab 4 as a start), Koole's *Call Center Optimization*, KCS on [KnowledgeOps](../knowledgeops/), AI operations on [LLMOps](../llmops/) |
| Portfolio | A metric dictionary, a staffing model with documented assumptions, and a before/after of one removed contact reason |

## Wrap-up

### Executive recap and cheat sheet

| Topic | Remember |
|---|---|
| What it is | The operations layer of customer support: queue, clock, loop |
| First decisions | Clock definitions; priority rubric; pooled vs split queues; who owns helpdesk changes |
| Capacity | Load = arrivals × AHT; Erlang C for live queues; add shrinkage; workload + Little's law for email |
| Metrics | SLA with open breaches; requester wait p80; backlog age; re-contact 7 days; verified automation resolution |
| AI | Assist agents first; disclose; human in one step; measure by re-contact; you own its answers |
| Watch-outs | Autoreplies stopping clocks; Pending parking; occupancy targets; claimed deflection; rule sprawl |
| Next actions | Write the metric dictionary; re-time a sample; forecast per interval; agree an OLA |

### A judgement call: a chat AI agent now, or fix the knowledge base first?

**Situation (illustrative).** A 30-agent team handles 9,000 chats a month. A vendor offers an AI agent priced per outcome, with a
pilot showing a 60% resolution rate. The knowledge base has 400 articles; an audit finds a quarter are out of date. Leadership wants
savings this quarter.

**Option A: launch the AI agent now.** Fast; the pilot looks good; some savings start immediately.
**Option B: spend six weeks fixing the top 60 articles and the hand-off design, then launch.** Slower; costs agent time now.

**Assumptions to state.** The 60% is the vendor's outcome count, including assumed resolutions; the AI answers from the knowledge
base; refunds and plan changes are among the top ten reasons.

**Reasoning.** With stale sources, some AI answers will be confidently wrong, and the company owns them
([Use case 3](#use-case-3-accountability-for-chatbot-answers-at-air-canada-documented-legal-dec)). The vendor's count cannot show customers who give up and email instead (Lab 3), so the savings
estimate is uncertain and its error is biased upward. Option B's cost is known; Option A's downside is spread across customers and
hard to see.

**Decision.** A narrow version of A plus B: launch the AI agent only on reasons whose articles were just verified and that carry no
financial or legal commitment, with re-contact measurement from day one, while fixing the rest; expand reason by reason when
verified resolution holds. The attractive choice (full launch now) is wrong not because AI is bad but because the measurement
would hide its failures. **Uncertainty:** if the stale articles are on rarely asked topics, Option A's risk is smaller.

### Learning objectives and mastery check

After this page you should be able to: **explain** what SupportOps owns and where its boundaries are; **calculate** staffing for a
live queue and a backlog; **design** an SLA clock that cannot be gamed; **evaluate** automation by verified resolution; and
**build** an escalation interface with engineering.

::: answer 1. Two reports disagree on first-reply SLA attainment (92% vs 61%). Name three definitional causes.
Business vs calendar hours; whether an autoreply stops the clock (a Zendesk autoreply, a Copilot add-on feature, does; Freshdesk's
automation "Send Reply" does not); whether unanswered tickets past target are counted.
:::

::: answer 2. 100 chats per 15 minutes, AHT 3.5 minutes. What is the load, and why are 24 agents not enough?
Load = 100 ÷ 15 × 3.5 = 23.33 erlangs. With 24 agents the margin is tiny, so random clusters create long queues: only about 21%
are answered in 20 seconds; about 28 agents are needed for 80/20 (Erlang C, Koole's example).
:::

::: answer 3. 240 email tickets arrive per business day and the target average time to first reply is half a day. What average waiting backlog does that imply?
By Little's law L = λW = 240 × 0.5 = 120 tickets awaiting a first reply on average.
:::

::: answer 4. A bot reports an 85% resolution rate. What would you measure before believing it?
The share of "resolved" sessions with no contact from the same customer on the same reason within a window (for example seven
days) on any channel, plus hand-off rate and quality. Vendor definitions can include assumed resolutions when the customer simply
leaves.
:::

::: answer 5. CSAT went from 72% to 80% this week on 11 and 10 ratings. Is that an improvement?
Not demonstrably: with about ten ratings the 95% interval spans tens of points (Lab 3: 43%–90% for 8 of 11). Report n and the
interval, and look at a longer period.
:::

::: answer 6. Engineering says escalations are low quality; support says engineering never answers. What do you set up?
An escalation template and severity rubric agreed by both, an OLA for acknowledgement and updates, tracking of escalation acceptance
rate and age, and a monthly service review using those numbers.
:::

### Conclusion

SupportOps is easy to underestimate because its outputs look administrative: a policy, a rule, a schedule, a dashboard. Underneath
is a precise discipline. Demand arrives at random, so capacity is a matter of queueing maths, not effort. Promises are measured by
clocks, so the definition of the clock is the real promise. Every ticket is evidence, so a support operation that only answers
and never feeds the causes back is paying for the same problem again and again. The label is informal and the boundaries with
customer success and CX are this Atlas's choice; the work itself is well defined. Get the queue, the clock and the loop right, measure
outcomes the customer would recognise, and let automation earn its place one verified reason at a time.

## Sources and further reading

All sources were opened on 2026-10-23. Product behaviour, plans and prices are as of October 2026; re-check them before relying on
a detail. Legal sources are orientation only.

[^zd-blog]: [Time to build a support operations team](https://www.zendesk.com/blog/customer-service/support/support-operations-team/) — Zendesk blog, Laura Shear, last updated 2021-01-26. Checked 2026-10-23.
[^gl-support]: [Support Team Handbook](https://handbook.gitlab.com/handbook/support/) — GitLab Handbook, last modified 2026-07-29. Checked 2026-10-23.
[^gl-css]: [Customer Support Systems](https://handbook.gitlab.com/handbook/eta/css/) — GitLab Handbook, last modified 2026-08-17. Checked 2026-10-23.
[^gl-metrics]: [Metrics definitions (Zendesk)](https://handbook.gitlab.com/handbook/eta/css/zendesk/metrics-definitions/) — GitLab Handbook, last modified 2026-07-14. Checked 2026-10-23.
[^hdi-scm]: [HDI Support Center Manager](https://www.thinkhdi.com/Education/Courses/HDI-Support-Center-Manager) — HDI, course page. Checked 2026-10-23.
[^zd-sla]: [Defining SLA policies](https://support.zendesk.com/hc/en-us/articles/4408829459866) — Zendesk help, undated live page. Checked 2026-10-23.
[^zd-sla-api]: [SLA Policies (API reference)](https://developer.zendesk.com/api-reference/ticketing/business-rules/sla_policies/) — Zendesk Developer Docs. Checked 2026-10-23.
[^zd-cond]: [Conditions reference](https://developer.zendesk.com/documentation/ticketing/reference-guides/conditions-reference/) — Zendesk Developer Docs. Checked 2026-10-23.
[^zd-oauth]: [OAuth Tokens for Grant Types](https://developer.zendesk.com/api-reference/ticketing/oauth/grant_type_tokens/) — Zendesk Developer Docs. Checked 2026-10-23.
[^zd-sched]: [Setting your schedule with business hours and holidays](https://support.zendesk.com/hc/en-us/articles/4408842938522) — Zendesk help. Checked 2026-10-23.
[^zd-trig]: [What is the difference between ticket triggers and automations?](https://support.zendesk.com/hc/en-us/articles/4408832924314) — Zendesk help. Checked 2026-10-23.
[^zd-route]: [Managing your omnichannel routing configuration](https://support.zendesk.com/hc/en-us/articles/4828787357210) — Zendesk help. Checked 2026-10-23.
[^zd-prob]: [Working with problem and incident tickets](https://support.zendesk.com/hc/en-us/articles/4408835103898) — Zendesk help. Checked 2026-10-23.
[^zd-cc]: [Adding a credit card identification field (last four digits)](https://support.zendesk.com/hc/en-us/articles/4408842751002) — Zendesk help. Checked 2026-10-23.
[^fd-sla]: [Understanding SLA Policies](https://support.freshdesk.com/en/support/solutions/articles/37626) — Freshdesk Support, modified 2026-08-20. Checked 2026-10-23.
[^jsm-cond]: [Set up SLA conditions](https://support.atlassian.com/jira-service-management-cloud/docs/set-up-sla-conditions/) — Atlassian Support, Jira Service Management Cloud. Checked 2026-10-23.
[^jsm-wfm]: [What is Workforce Management in Jira Service Management?](https://support.atlassian.com/jira-service-management-cloud/docs/what-is-workforce-management-in-jira-service-management/) — Atlassian Support. Checked 2026-10-23.
[^koole]: [Call Center Optimization, first chapters (PDF)](https://www.gerkoole.com/CCO/downloads/CCO_Koole_first_chapters.pdf) — Ger Koole, MG books, Amsterdam, 2013 (sections 1.2, 2.1–2.5). Checked 2026-10-23.
[^aam07]: [The Modern Call Center: A Multi-Disciplinary Perspective on Operations Management Research](https://www.columbia.edu/~ww2040/4615S13/AAM07.pdf) — Zeynep Aksin, Mor Armony and Vijay Mehrotra, *Production and Operations Management* 16(6), 665–688, 2007 (course copy). Checked 2026-10-23.
[^little]: [Little's Law as Viewed on Its 50th Anniversary](https://people.cs.umass.edu/~emery/classes/cmpsci691st/readings/OS/Littles-Law-50-Years-Later.pdf) — John D. C. Little, *Operations Research* 59(3), 536–549, 2011, doi 10.1287/opre.1110.0940 (course copy). Checked 2026-10-23.
[^fpp-calls]: [Forecasting: Principles and Practice (3rd ed.), 12.1 Complex seasonality](https://otexts.com/fpp3/complexseasonality.html) — Rob J Hyndman and George Athanasopoulos, OTexts, 2021. Checked 2026-10-23.
[^iso18295-1]: [ISO 18295-1:2017 Customer contact centres — Part 1: Requirements for customer contact centres](https://web.archive.org/web/20260217234753/https://www.iso.org/standard/64739.html) — ISO, 2017, confirmed 2023 (iso.org page read via the Internet Archive). Checked 2026-10-23.
[^iso18295-2]: [ISO 18295-2:2017 Customer contact centres — Part 2: Requirements for clients using the services of customer contact centres](https://web.archive.org/web/20230620103423/https://www.iso.org/standard/64740.html) — ISO, 2017 (archived page). Checked 2026-10-23.
[^iso10002]: [ISO 10002:2018 Quality management — Customer satisfaction — Guidelines for complaints handling in organizations](https://web.archive.org/web/20251130144903/https://www.iso.org/standard/71580.html) — ISO, 2018 (archived page). Checked 2026-10-23.
[^copc]: [COPC Inc. Announces Release 7.0 of the COPC Customer Experience (CX) Standard](https://www.copc.com/copc-inc-announces-release-7-0-of-the-copc-customer-experience-cx-standard) — COPC Inc. press release, 2021-08-05 (superseded release). Checked 2026-10-23.
[^copc-r8]: [Release 8.0 Frequently Asked Questions](https://www.copc.com/copc-standards/r8-faqs/) — COPC Inc., live page. Checked 2026-10-23.
[^kcs]: [The Double Loop Process (KCS v6 Practices Guide)](https://library.serviceinnovation.org/KCS/KCS_v6/KCS_v6_Practices_Guide/030/025) — Consortium for Service Innovation. Checked 2026-10-23.
[^swarm]: [Why Intelligent Swarming?](https://library.serviceinnovation.org/Intelligent_Swarming/Practices_Guide/15_Why_Intelligent_Swarming) — Consortium for Service Innovation, Intelligent Swarming Practices Guide. Checked 2026-10-23.
[^gartner-ss]: [Gartner Says Only 9% of Customers Report Solving Their Issues Completely via Self-Service](https://web.archive.org/web/20240909151455/https://www.gartner.com/en/newsroom/press-releases/2019-09-25-gartner-says-only-9--of-customers-report-solving-thei) — Gartner press release, 2019-09-25 (read via the Internet Archive). Checked 2026-10-23.
[^klarna-2024]: [Klarna AI assistant handles two-thirds of customer service chats in its first month](https://www.klarna.com/international/press/klarna-ai-assistant-handles-two-thirds-of-customer-service-chats-in-its-first-month/) — Klarna press release, 2024-02-27 (company claims). Checked 2026-10-23.
[^klarna-2025]: [Klarna Is Hiring Customer Service Agents After AI Couldn't Cut It on Calls, According to the Company's CEO](https://www.entrepreneur.com/business-news/klarna-ceo-reverses-course-by-hiring-more-humans-not-ai/491396) — Entrepreneur, Sherin Shibu, 2025-05-09 (report of a Bloomberg interview). Checked 2026-10-23.
[^blr]: [Generative AI at Work](https://digitaleconomy.stanford.edu/publication/generative-ai-at-work/) — Erik Brynjolfsson, Danielle Li and Lindsey R. Raymond, *The Quarterly Journal of Economics* 140(2), 889–942, 2025, doi [10.1093/qje/qjae044](https://doi.org/10.1093/qje/qjae044) (the Stanford page, labelled "Working Paper", shows the published abstract; earlier: NBER Working Paper 31161, 2023). Checked 2026-10-23.
[^fin-outcomes]: [Fin AI Agent outcomes](https://www.intercom.com/help/en/articles/8205718-fin-ai-agent-outcomes) — Intercom Help (undated). Checked 2026-10-23.
[^intercom-pricing]: [Pricing](https://www.intercom.com/pricing) — Intercom, live page. Checked 2026-10-23.
[^aircanada]: [Moffatt v. Air Canada, 2024 BCCRT 149](https://decisions.civilresolutionbc.ca/crt/crtd/en/525448/1/document.do) — Civil Resolution Tribunal of British Columbia (small claims), reasons for decision, 2024-02-14, paras 27–28. Checked 2026-10-23.
[^aiact3]: [Article 3: Definitions](https://artificialintelligenceact.eu/article/3/) — EU AI Act, unofficial consolidated text (artificialintelligenceact.eu), points (3) provider and (4) deployer. Checked 2026-10-23.
[^aiact50]: [Article 50: Transparency Obligations for Providers and Deployers of Certain AI Systems](https://artificialintelligenceact.eu/article/50/) — EU AI Act, unofficial consolidated text (artificialintelligenceact.eu). Checked 2026-10-23.
[^goodwin-50]: [Not Delayed, Not Deferred: EU AI Act Transparency Obligations Are Now in Force](https://www.goodwinlaw.com/en/insights/publications/2026/08/alerts-technology-dpc-eu-ai-act-transparency-obligations-now-in-force) — Goodwin Procter alert, 2026-08-03. Checked 2026-10-23.
[^gdpr5]: [Art. 5 GDPR: Principles relating to processing of personal data](https://gdpr-info.eu/art-5-gdpr/) — gdpr-info.eu (unofficial text). Checked 2026-10-23.
[^zammad]: [zammad/zammad](https://github.com/zammad/zammad) — GitHub, AGPL-3.0. Checked 2026-10-23.
[^osticket]: [osTicket/osTicket](https://github.com/osTicket/osTicket) — GitHub, GPL-2.0. Checked 2026-10-23.
[^freescout]: [freescout-help-desk/freescout](https://github.com/freescout-help-desk/freescout) — GitHub, AGPL-3.0. Checked 2026-10-23.
[^chatwoot]: [chatwoot/chatwoot](https://github.com/chatwoot/chatwoot) — GitHub (check the repository's licence file before use). Checked 2026-10-23.

**Further reading.**

- Ger Koole, *Call Center Optimization* (MG books, 2013), the full book beyond the free chapters.
- Noah Gans, Ger Koole and Avishai Mandelbaum, "Telephone Call Centers: Tutorial, Review, and Research Prospects",
  *Manufacturing & Service Operations Management* 5(2), 2003 (doi 10.1287/msom.5.2.79.16071); not opened for this page.

**Changelog.** Vendor rows (Zendesk, Freshdesk, Atlassian, Intercom) and the EU AI Act row are due for re-verification by
2027-01-23.

- 2026-10-23, first version: research and ledger (`research/supportops-ledger.md`), four labs executed on synthetic data, eight
  diagrams; not yet independently fact-checked.
- 2026-10-23, round 1 revision (`reviews/supportops-r1.md`, response `reviews/supportops-r1-response.md`): AI-assistance study
  cited in its 2025 journal version; COPC Release 8.0; Artefact 1 filter, catch-all, OAuth scope and curl error handling; Zendesk
  skills-timeout, autoreply and plan conditions; full swarming quote; AI Act provider and deployer; primary Air Canada decision;
  Klarna and Air Canada told once; Lab 1 leaves not-yet-due tickets out (re-run); global coverage; two diagram fixes.
- 2026-10-23, post-score polish (`reviews/supportops-polish.md`): Scenario 4 matches Lab 2 (48 agents); AI Act provider
  definition completed; DOI link added; Air Canada PDF re-opened.
