The Ops Atlas xOps School

Business & Growth Established term Partly verified

SupportOps

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.

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.

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.

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), survey design and journey-wide feedback (CXOps), the knowledge practice itself (KnowledgeOps), production incident command (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

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

Link to section “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”.[1] 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, and measurement and governance across the whole journey to 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.
  • Not incident management. When production is down, an incident commander runs the response on 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. This page owns the self-service channel and its deflection metrics.

Where SupportOps comes from and where it sits

Link to section “Where SupportOps comes from and where it sits”

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.[2] 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)”.[2] 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.[3] International standards followed for contact centres (ISO 18295, 2017) and for complaints handling (ISO 10002).[4][5]

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).[6][7]

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

Link to section “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.
Figure 1. SupportOps among its neighbours: what flows across each boundary
survey methodticket insightescalations, risk signalscapture and reusestatus, ETAbugs, requestsshared queueing mathsCXOps: journey-widefeedback, survey designSupportOps: tickets, SLAs,routing, staffingCustomerOps: health,renewals, success plansKnowledgeOps: KCS articles,runbooksIncidentOps: productionincidentsProduct and engineeringITOps: internal IT servicedesk
Diagram source (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 Existing customers Reactive requests, SLAs Health scores, renewals, success plans Ticket trends and escalations feed health scores
CXOps CSAT and feedback Transactional CSAT after a ticket Survey design, NPS/CES, journey-wide loop CXOps sets method; SupportOps applies it
KnowledgeOps Articles, KCS Self-service channel, deflection metrics Knowledge lifecycle, KCS practice Agents capture and improve articles in the flow of work
IncidentOps Outages Mass tickets, customer status, problem linking Incident command, mitigation, reviews Liaison role; one incident ↔ many tickets
ITOps Ticket queues, SLAs External customers Internal IT service desk, ITSM practices Same staffing maths; different users and processes
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 Chat-driven work Customer messaging channels Operating systems through team chat Escalation alerts often land in team chat
LLMOps AI answers Governance of AI agents in support Operating LLM applications (evaluation, retrieval) SupportOps sets resolution and safety rules; LLMOps runs the system

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

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.[8] 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.
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
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

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.

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.[9][10]

Figure 2. Ticket statuses (which clocks run in each is explained below)
arrivespicked upask customerthird partyreopenafter N daysNewOpenPendingOnHoldSolvedClosed
Diagram source (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.[9] 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.

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

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

Figure 3. Reference architecture of a support operation
needs a humandefect or expert needfix, workaroundcapture, improvestaffed capacityevents, timestampsactualsChannels: email, form, chat,phone, in-appIntake: identity, account,entitlementSelf-service and AI agentTriage: type, product area,priorityRouting: skills, capacity,queue orderAgents: L1 front line, L2specialistsEscalation to engineeringissue trackerKnowledge baseWorkforce management:forecast, scheduleData and reporting: metricdictionary
Diagram source (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.
  • 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.[11]

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

Link to section “End-to-end workflow: happy path and exception path”
Figure 4. From first contact to fix: a request that escalates to engineering
EngineeringL2 expertL1 agentCustomerAI agenthand-off + transcript to L1problem1article2not solved3asks for logs4logs5escalates6files defect7workaround8workaround, ETA9workaround, ETA10fix shipped11fix live12confirms, solves13
Diagram source (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
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”.[12]

Capacity: the queueing maths behind every SLA

Link to section “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

Link to section “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.[8] 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.[8]

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.[13] 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.[14] Staffing therefore works per interval (usually 15 or 30 minutes), not per day.[8]

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.[2] 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.[8]

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.[2] Large pools reach occupancy people cannot sustain for long; Koole notes that occupancy near 100% “can only occur for short periods”.[8]

“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.[8] 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.[8] The first definition ignores abandoned calls; it “clearly gives a perverse incentive” because a long-waiting caller who hangs up improves the number.[8] 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.[8]

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”.[8]

  • 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).[8] 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.[8] 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.[2]

Figure 5. The workforce management loop: from history to tomorrow’s schedule
update models and eventsHistory: volume and AHT perintervalForecast: volume and AHT,with eventsRequired agents per interval(Erlang C, simulation,workload)Add shrinkage: agents toscheduleSchedule: shifts, breaks,skillsIntraday: compare actuals,adjustVariance review: forecasterror, adherence
Diagram source (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

Link to section “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.[8] 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).[15]

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.[14]
  • 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).

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

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).[16]
  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.

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.[9] 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.[17]
  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).[9] Freshdesk does not count replies sent by its automation “Send Reply” action, which are “treated as system-generated messages rather than agent responses”.[18] 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.[9]
  5. Order policies from most to least restrictive when a tool applies the first match.[9]
  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

Link to section “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”.[19] 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.

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”.[20] 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.
  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.

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).
  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.

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

  1. Template (see 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.[12]
  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.

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.[21] 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 includes this choice.

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[4] Contact-centre management system and audits
ISO 18295-2:2017 International standard Requirements for organisations using contact-centre services[11] Contracting and governing outsourced support
ISO 10002:2018 International guidelines “guidelines for the process of complaints handling”[5] Complaint process design
COPC CX Standard Proprietary industry standard “a performance management system used to improve operations that support the customer experience”;[22] 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[23] 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[24] Knowledge capture and reuse; taught on KnowledgeOps
Intelligent Swarming Practice framework (same Consortium) Collaboration model replacing tiered escalation[21] Complex-case handling
Queueing models (Erlang C, Erlang A, Little’s law) Mathematics Staffing, waiting, backlog[2][13] Capacity planning
ITIL 4 practices IT service management framework Incident, problem, request, service desk Internal IT service desks; see 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.

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[25][26][27][28] 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)[16][29] 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 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”.[29] 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).[30]

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”.[31] (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. 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.[32] 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); the general point is covered on 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.[33][34] 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.[35] 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.[23] Operating the language-model system itself (evaluation sets, retrieval quality, prompt changes) is covered on LLMOps; SupportOps sets the business rules and measures the service.

Reference implementation: operating artefacts

Link to section “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)

Link to section “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).[36]

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.[37] 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).

{
  "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).[38] Replace example with your subdomain; keep the token in an environment variable, never in the repository; run it against a sandbox first.

# 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);[36] 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.[9]

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.

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)

Link to section “Artefact 3: priority rubric and routing rules (tool-neutral)”

Example status: YAML syntax-checked; illustrative configuration to translate into your helpdesk’s rule engine.

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

Link to section “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.

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.

Lab 1 (beginner): SLA clocks and what they hide

Link to section “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).

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
  1. Save the script as sla.py.

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

"""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)}")
  1. Run python3 sla.py.

Expected output.

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

Link to section “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).

"""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%}")
  1. Run python3 erlang.py.

Expected output.

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%;[8] 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

Link to section “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).

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
  1. Save the script as metrics.py.

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

"""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}")
  1. Run python3 metrics.py.

Expected output.

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.[32] 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

Link to section “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).

"""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%}")
  1. Run python3 simulate.py.

Expected output.

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,[2][8] 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

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)

Link to section “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”.[6] 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”.[6][7]

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.[7] It also publishes the definitions it uses for each Zendesk clock.[10]

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)

Link to section “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.[39] 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.[40]

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).

Link to section “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”.[41]

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)

Link to section “Scenario 4: a launch week that nearly doubles chat volume (illustrative)”

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

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

Link to section “Scenario 5: plan-based SLAs and an OLA with engineering (illustrative)”

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

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 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 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.

  • 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”.[42] 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.
  • 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”.[43] 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-style controls or ISO 18295 certification.[4]
  • AI agents. Disclosure, approved sources and human hand-off, as in Automation and AI.
  • Regulated sectors (health, finance, government) add complaint-handling rules, call-recording consent and data residency; check them per jurisdiction.

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.[32] 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.[8] Environmental impact is usually small; where it matters, see GreenOps.

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
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

Link to section “Worked runbook: a backlog surge after a release”
Figure 6. Runbook: from a backlog alert to recovery and prevention
yesnoAlert: backlog over thresholdor SLA breaches risingOne main cause?Declare mass issue: problemticket, link incidentsStatus message and macro,engineering linkCapacity response: overtime,borrow staff, pause lowpriorityRecovery plan: clear by ageand priority, daily burn-downReview: forecast, releasecalendar, escalation timing
Diagram source (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.

  • “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).[8]
  • “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.[31][40]
  • “Support should not bother engineering.” Then engineering hears about defects from churn. Design the interface instead.

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.

Figure 7. Decision tree: how much SupportOps, and tiers or swarming
noyesnoyesyesno10+ people or severalchannels?Contract SLAs or growingbacklog?Part-time ownerDedicated SupportOps team95%+ known, solved on firstcontact?Tiers plus escalation templateSwarming or hybrid
Diagram source (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.

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

Figure 8. Maturity levels of a support operation
1 Reactive: shared inbox, noclocks2 Defined: helpdesk, writtenSLA clocks, taxonomy3 Managed: forecasts,staffing model, QA, metricdictionary4 Integrated: escalationOLAs, problem loop, verifiedautomation5 Adaptive: interval planning,experiments, causesremoved
Diagram source (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
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.

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

Escalation to engineering (paste into the issue tracker):

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:

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; update customers at the promised time; solve via the problem ticket; review within five business days.

Question SupportOps CustomerOps CXOps 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)

Is SupportOps a job title? Yes, mostly as “support operations” (manager, analyst, specialist). The one-word form is informal shorthand.[1][6]

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.[32]

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.

  • Established: multi-skill staffing and routing, Erlang A and simulation, time-varying staffing; see the operations research survey for entry points.[2]
  • Active practice, evidence still thin: AI agents with outcome-based pricing; AI drafting and summarisation for agents (one large field study in one firm);[31] 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.[33][41]
  • Marketing claims to test before believing: “autonomous support”, fixed percentage deflection promises, and benchmark CSAT figures without a stated survey method.
Stage Do this
1-day primer Read The ticket lifecycle and Capacity; 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, AI operations on LLMOps
Portfolio A metric dictionary, a staffing model with documented assumptions, and a before/after of one removed contact reason
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?

Link to section “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). 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.

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.

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.

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).

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.

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.

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.

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.

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.

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.

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.

  1. Time to build a support operations team — Zendesk blog, Laura Shear, last updated 2021-01-26. Checked 2026-10-23. ↩︎ ↩︎

  2. The Modern Call Center: A Multi-Disciplinary Perspective on Operations Management Research — Zeynep Aksin, Mor Armony and Vijay Mehrotra, Production and Operations Management 16(6), 665–688, 2007 (course copy). Checked 2026-10-23. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  3. HDI Support Center Manager — HDI, course page. Checked 2026-10-23. ↩︎

  4. ISO 18295-1:2017 Customer contact centres — Part 1: Requirements for customer contact centres — ISO, 2017, confirmed 2023 (iso.org page read via the Internet Archive). Checked 2026-10-23. ↩︎ ↩︎ ↩︎

  5. ISO 10002:2018 Quality management — Customer satisfaction — Guidelines for complaints handling in organizations — ISO, 2018 (archived page). Checked 2026-10-23. ↩︎ ↩︎

  6. Support Team Handbook — GitLab Handbook, last modified 2026-07-29. Checked 2026-10-23. ↩︎ ↩︎ ↩︎ ↩︎

  7. Customer Support Systems — GitLab Handbook, last modified 2026-08-17. Checked 2026-10-23. ↩︎ ↩︎ ↩︎

  8. Call Center Optimization, first chapters (PDF) — Ger Koole, MG books, Amsterdam, 2013 (sections 1.2, 2.1–2.5). Checked 2026-10-23. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  9. Defining SLA policies — Zendesk help, undated live page. Checked 2026-10-23. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  10. Metrics definitions (Zendesk) — GitLab Handbook, last modified 2026-07-14. Checked 2026-10-23. ↩︎ ↩︎

  11. ISO 18295-2:2017 Customer contact centres — Part 2: Requirements for clients using the services of customer contact centres — ISO, 2017 (archived page). Checked 2026-10-23. ↩︎ ↩︎

  12. Working with problem and incident tickets — Zendesk help. Checked 2026-10-23. ↩︎ ↩︎ ↩︎

  13. Little’s Law as Viewed on Its 50th Anniversary — John D. C. Little, Operations Research 59(3), 536–549, 2011, doi 10.1287/opre.1110.0940 (course copy). Checked 2026-10-23. ↩︎ ↩︎

  14. Forecasting: Principles and Practice (3rd ed.), 12.1 Complex seasonality — Rob J Hyndman and George Athanasopoulos, OTexts, 2021. Checked 2026-10-23. ↩︎ ↩︎

  15. Setting your schedule with business hours and holidays — Zendesk help. Checked 2026-10-23. ↩︎

  16. Managing your omnichannel routing configuration — Zendesk help. Checked 2026-10-23. ↩︎ ↩︎

  17. Set up SLA conditions — Atlassian Support, Jira Service Management Cloud. Checked 2026-10-23. ↩︎

  18. Understanding SLA Policies — Freshdesk Support, modified 2026-08-20. Checked 2026-10-23. ↩︎

  19. What is the difference between ticket triggers and automations? — Zendesk help. Checked 2026-10-23. ↩︎

  20. Gartner Says Only 9% of Customers Report Solving Their Issues Completely via Self-Service — Gartner press release, 2019-09-25 (read via the Internet Archive). Checked 2026-10-23. ↩︎

  21. Why Intelligent Swarming? — Consortium for Service Innovation, Intelligent Swarming Practices Guide. Checked 2026-10-23. ↩︎ ↩︎

  22. 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. ↩︎

  23. Release 8.0 Frequently Asked Questions — COPC Inc., live page. Checked 2026-10-23. ↩︎ ↩︎

  24. The Double Loop Process (KCS v6 Practices Guide) — Consortium for Service Innovation. Checked 2026-10-23. ↩︎

  25. zammad/zammad — GitHub, AGPL-3.0. Checked 2026-10-23. ↩︎

  26. osTicket/osTicket — GitHub, GPL-2.0. Checked 2026-10-23. ↩︎

  27. freescout-help-desk/freescout — GitHub, AGPL-3.0. Checked 2026-10-23. ↩︎

  28. chatwoot/chatwoot — GitHub (check the repository’s licence file before use). Checked 2026-10-23. ↩︎

  29. What is Workforce Management in Jira Service Management? — Atlassian Support. Checked 2026-10-23. ↩︎ ↩︎

  30. Pricing — Intercom, live page. Checked 2026-10-23. ↩︎

  31. 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 (the Stanford page, labelled “Working Paper”, shows the published abstract; earlier: NBER Working Paper 31161, 2023). Checked 2026-10-23. ↩︎ ↩︎ ↩︎

  32. Fin AI Agent outcomes — Intercom Help (undated). Checked 2026-10-23. ↩︎ ↩︎ ↩︎ ↩︎

  33. Article 50: Transparency Obligations for Providers and Deployers of Certain AI Systems — EU AI Act, unofficial consolidated text (artificialintelligenceact.eu). Checked 2026-10-23. ↩︎ ↩︎

  34. Not Delayed, Not Deferred: EU AI Act Transparency Obligations Are Now in Force — Goodwin Procter alert, 2026-08-03. Checked 2026-10-23. ↩︎

  35. Article 3: Definitions — EU AI Act, unofficial consolidated text (artificialintelligenceact.eu), points (3) provider and (4) deployer. Checked 2026-10-23. ↩︎

  36. SLA Policies (API reference) — Zendesk Developer Docs. Checked 2026-10-23. ↩︎ ↩︎

  37. Conditions reference — Zendesk Developer Docs. Checked 2026-10-23. ↩︎

  38. OAuth Tokens for Grant Types — Zendesk Developer Docs. Checked 2026-10-23. ↩︎

  39. 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. ↩︎

  40. Klarna Is Hiring Customer Service Agents After AI Couldn’t Cut It on Calls, According to the Company’s CEO — Entrepreneur, Sherin Shibu, 2025-05-09 (report of a Bloomberg interview). Checked 2026-10-23. ↩︎ ↩︎

  41. Moffatt v. Air Canada, 2024 BCCRT 149 — Civil Resolution Tribunal of British Columbia (small claims), reasons for decision, 2024-02-14, paras 27–28. Checked 2026-10-23. ↩︎ ↩︎

  42. Art. 5 GDPR: Principles relating to processing of personal data — gdpr-info.eu (unofficial text). Checked 2026-10-23. ↩︎

  43. Adding a credit card identification field (last four digits) — Zendesk help. Checked 2026-10-23. ↩︎

Related Ops

CustomerOps

CustomerOps is an unstandardised label. This page uses it for customer success operations: the data, processes and systems that help existing customers reach value, so renewals and expansion become predictable and churn is seen early.

CXOps

CXOps (customer experience operations) is an unstandardised label. This page uses it for the system that turns customer feedback into owned, verified fixes across the whole journey: survey and signal design, closing the loop, journey governance and honest experience metrics.

KnowledgeOps

KnowledgeOps is running an organisation's working knowledge (answers, runbooks, procedures) as an operated asset: captured in the flow of work, owned, reviewed in proportion to risk, findable, access-controlled and retired on purpose.

ITOps

ITOps (IT operations) is the function that keeps an organisation's IT services running: it handles requests and incidents, removes the causes of repeat failures, controls changes and keeps an accurate map of the estate, often through ITIL-style ITSM practices.

IncidentOps

IncidentOps is a rare, informal label for incident management: declaring, coordinating, communicating and learning from unplanned service disruptions. This page teaches that established practice, with a focus on human coordination under pressure.

RevOps

RevOps (revenue operations) aligns marketing, sales and customer success around one set of funnel definitions, one trusted customer record, governed hand-offs and one forecast, so the revenue process can be measured and improved end to end.

ChatOps

ChatOps is the practice of running operational work through shared chat: bots post the events people need and run allow-listed commands on request, so actions, results and the discussion around them are visible, permissioned and auditable.

LLMOps

LLMOps is the practice of running applications built on large language models in production: versioning prompts, models and retrieval together, gating every change on evaluations, tracing each request, and keeping prompt injection, latency and token use in check.

Practise and get certified

From xOps School

Practise SupportOps and get certified

The SupportOps track on xOps School (part of the Coffee Pass) has study notes, a 25-question practice quiz with explanations, and a verifiable certificate when you score 70% or more. Sign in with Google to start.

For teams

Instructor-led training

Live batches for your team, with completion certificates and reports for L&D/HR.

Source: master.md (the editorial source of this page) · built 2026-10-23 · diagrams rendered with @mermaid-js/mermaid-cli 11.17.0 (mermaid 11.17.2)