Part 3 of 7 · Ticket router series ~5 min read

How a ticket gets routed

The read step handed the router three tags: a topic, an urgency, and a tone. Now the router has to turn those into a decision — which team, and how loud. It reads one ticket at a time, looks up the team for the topic, checks the VIP list and the priority rules, and picks one of four moves. The whole decision is plain Python. The model call already happened on intake. Every rule lives in the Drive folder, where a manager can edit it without a deploy.

Key takeaways

  • The router runs once per ticket, right after the read step tags it.
  • The topic-to-team map lives in the rules sheet; the urgency words and VIP list live in the rules doc.
  • Four moves per ticket: route, priority, escalate, or hold.
  • An unclear topic or a half-empty ticket goes to hold — a human triage lane, never a guess.
  • The router never calls a model. The decision is entirely from the rules.

The decision flow, per ticket

Decision flow per ticket after the read step A vertical decision flow diagram. At the top, an input box "Tagged ticket" with the ticket's customer, topic, urgency, and tone from the read step. Below that, a step "Is the topic clear?" — if the model returned unsure, or the ticket body is nearly empty, route to "Hold" (drop in the human triage lane). If the topic is clear, continue. The next step "Look up team for topic" — pulls the team from the rules sheet; for example billing maps to finance, login maps to support. The next step "Is the customer a VIP?" — checks the customer against the VIP list in the rules doc; a VIP raises the floor on urgency. The next step "Apply the priority rules" — checks the urgency and tone against the rules doc: an angry tone plus high urgency, or a VIP outage, lifts the ticket. Based on that, the router picks the move. If urgency is low or medium and tone is calm, route to "Route" (the team's normal queue). If urgency is high or the customer is a VIP, route to "Priority" (top of the team's queue, ping the lead). If it is angry and high, or a VIP outage, route to "Escalate" (flag loudly for a manager). Each terminal box — Hold, Route, Priority, Escalate — writes the move and the chosen team to DynamoDB and hands off to the dispatch step. A note at the bottom: the rules doc holds every rule; the router only enforces them — change a rule in the doc and the next ticket uses the new value. Tagged ticket customer · topic · urgency · tone Step 1 Is the topic clear? unsure or empty → hold Step 2 Look up team for topic read the rules sheet Step 3 Is the customer a VIP? check the VIP list in the doc Step 4 Apply the priority rules calm + low → route angry + high → escalate Step 5 High urgency or VIP? yes → jump the queue Hold human triage lane Route team’s normal queue Priority top of queue, ping lead Escalate angry + high, or VIP down unsure hold angry route priority The rules doc holds every rule — change one and the next ticket uses the new value.
Fig 3. The router’s decision tree, per ticket. Five steps decide which of four moves applies and which team it goes to. The rules hold every threshold; the router only enforces them.

Topic to team: the map is in the sheet

The rules sheet has one row per topic. Each row names the topic and the team that owns it: “billing → finance, login problems → support, bug report → engineering, feature request → product, sales question → sales.” When the read step tags a ticket with a topic, the router looks up that row and gets the team. If a topic has no row — someone added a new topic to the model’s list but not the sheet — the router treats it as unclear and holds the ticket rather than dropping it somewhere arbitrary.

Per-customer overrides exist too. The VIP list can pin a named customer to a named person (“Acme always goes to Dana”), so a key account’s tickets skip the general queue and land with the person who knows them. That override beats the topic map for that customer.

Four moves, always

Every ticket lands in exactly one of four buckets. The names are plain on purpose.

  • Route. A normal ticket — clear topic, calm tone, nothing urgent. Send it to the chosen team’s normal queue. Most tickets, most days, route. Nobody is pinged; it just shows up in the right place.
  • Priority. The urgency is high, or the customer is a VIP, but the tone is still civil. Send it to the same team, but put it at the top of their list and ping the team lead so it isn’t missed. A payment that failed, a deadline mentioned, a key account asking — these are priority.
  • Escalate. Angry and urgent together, or a VIP reporting an outage. Flag it loudly — the ticket goes to the top and a manager is pinged directly, not just the team lead. This is the small set of tickets where being a minute late is genuinely costly, so the router makes noise on purpose.
  • Hold. The topic came back unsure, or the ticket is nearly empty (“help” with no detail), or it looks like spam. Don’t guess. Drop it in a small triage lane where a human glances at it and sends it on. A wrong route costs more than a held ticket, because a wrong route looks handled when it isn’t.

Why the routing decision uses no model

The router could call a model again to pick the team. It doesn’t. Two reasons. First, the routing decision should be the one part a manager can fully predict — if the sheet says billing goes to finance, it goes to finance, every time. A model in that loop would add variance the team can’t reason about, and “why did this go there?” would have no clean answer. Second, the reading is already done; the topic, urgency, and tone are in hand. Turning three tags into a team is a lookup and a few if statements, not a job for a model.

So Bedrock fires exactly once per ticket — on the read step in Part 2. The router itself is plain Python that reads a sheet, checks a list, and picks a move. That keeps the routing cheap, fast, and explainable.

What the router writes down

Every decision is recorded. The router writes a row to the tr-routes DynamoDB table: (ticket_id, topic, urgency, tone, team, move, decided_at). That row is what the hand-off step reads to know where to send the ticket, and what the weekly digest counts to show volume by topic and team. It’s also the “before” picture if a human reassigns the ticket later — which is exactly what Part 5 covers.

Next post: how the chosen move actually reaches the right team — the channel, the queue position, the context attached, and the guardrails on every hand-off.

All posts