Salesforce Email-to-Case AI Classification ② What Happens When Intent Changes Inside the Same Email Thread?

In Part 1, I deliberately kept the customer requirement small.

When Salesforce Email-to-Case creates a Case from an inbound email, AI reads the message and determines the Level 1 and Level 2 Category. Once the Category is set, the existing Salesforce Assignment Rule continues the workflow.

On paper, that is a clean design.

The harder questions begin after the first classification.

A customer who started with a Billing issue can reply in the same email thread with something completely different:

“The billing issue is resolved. But now the device will not power on.”

From Salesforce’s point of view, the email conversation is still continuing.

But from an operational point of view, should we still treat it as the same inquiry?

Following that question led me beyond simple Category automation.

How much judgment should AI own? If the model changes its judgment, should the Case Category, Queue, owner, SLA, and history change immediately as well? And how much of Salesforce’s existing Email-to-Case threading should we disturb just because the business intent has changed?

My conclusion was that not every new complexity belongs inside the LLM or an Agent.

Interpreting ambiguous language and applying an exact state transition are different kinds of work. One is probabilistic judgment. The other involves authority, consistency, transaction boundaries, and operational side effects.

1. The Same Email Thread Does Not Mean the Same Business Intent

Customers do not write emails while thinking about the Salesforce data model.

They may start with a billing problem, exchange a few messages, then mention a delivery issue. They may withdraw that second issue a few minutes later. Or they may keep using the same thread after the original inquiry is already resolved and introduce a new product failure.

A simple sequence might look like this.

09:00

“This month’s charge looks wrong.”

09:04

“Also, the shipment has not arrived.”

09:07

“The shipment has arrived. Please look into the billing issue again.”

Technically, this can remain one continuous email conversation. Operationally, the important intent may have moved several times in seven minutes.

That distinction became fundamental to the design.

Email thread identity is not the same as business intent.

Salesforce is already good at maintaining the relationship between inbound email and Case. The AI problem is not to rebuild that thread. It is to understand what the customer is asking for now inside that thread.

If those two concerns are treated as one problem from the start, a small classification feature can quickly turn into a project that redesigns Email-to-Case threading itself.

2. Why Not Reclassify Every Time a New Email Arrives?

The first solution that comes to mind is straightforward.

Whenever a new EmailMessage arrives, send the recent conversation back to the model and calculate the latest Category again.

That sounds reasonable at first. The model always sees fresh context, and if the customer’s intent changes, the Case can be routed to the new team quickly.

The problem shows up once this enters real operations.

Using the sequence above, even a perfectly accurate model might produce:

Billing → Shipping → Billing

If Category drives an Assignment Rule, those are not necessarily three harmless field updates.

The owning Queue may change. If an agent has already picked up the Case, work may be duplicated or interrupted. Another team may suddenly receive a Case that disappears again two minutes later.

The customer only added a few pieces of information. The system may interpret those messages as three separate operational state transitions.

Getting the newest Category right as quickly as possible is not the same objective as keeping the service workflow stable.

This is where I stopped treating the problem as classification accuracy alone.

A stronger LLM does not automatically solve it. The design also needs to decide when a model judgment is allowed to become a real business-state change.

A single email thread where customer intent moves from Billing to Shipping and back to Billing, showing how immediate AI updates can destabilize category and queue assignment.
The technical email thread can remain continuous while the customer's business intent moves. Applying every model judgment immediately can make Category, Queue, and ownership oscillate with it.

3. High Confidence Still Does Not Grant Workflow Authority

The next tempting answer is a confidence threshold.

Suppose the model returns:

{
  "category_key": "product_support_device_failure",
  "confidence": 0.97,
  "reason": "The customer states that the previous billing issue is resolved and reports a new device malfunction."
}

It is easy to turn that into a rule:

If confidence is above 0.9, automatically change the Category.

But what does 0.97 actually mean?

The model may be highly confident that the current message describes a Product Support issue. That does not automatically mean it has authority to end the previous agent’s work, move the Case, change the owning Queue, reset an SLA, create history, and notify the customer.

Model confidence is not workflow authority.

The model’s judgment about meaning and the application’s decision about what actions are permitted belong to different layers.

I am comfortable letting the LLM own the former. I would rather keep the latter inside application logic and explicit business rules whenever possible.

4. The LLM Did Not Need to Traverse the Category Hierarchy Either

There was also a practical simplification inside the classification step itself.

The customer’s taxonomy had two levels.

General Support

  • Account
  • Login
  • Usage

Billing

  • Payment Failure
  • Refund
  • Invoice

Product Support

  • Installation
  • Device Failure
  • Configuration

One approach is to ask the model to choose Level 1 first and then infer Level 2 beneath that parent.

I do not think the model needs to perform that hierarchy traversal if the taxonomy is already known.

Two separate classification decisions create two opportunities for inconsistency. The parent and child criteria may drift, and the application still has to validate that the final combination is legal.

I prefer flattening the valid leaves into a bounded choice set:

general_support_account
general_support_login
general_support_usage

billing_payment_failure
billing_refund
billing_invoice

product_support_installation
product_support_device_failure
product_support_configuration

For a task this bounded, I would also start by evaluating a lightweight model rather than assuming a large model is required. The response should be constrained as Structured Output rather than free-form prose.

The model only needs to choose one valid semantic key:

{
  "category_key": "billing_refund",
  "confidence": 0.91
}

The application then performs the exact mapping:

billing_refund
        ↓
Level 1 = Billing
Level 2 = Refund

The LLM selects; the code maps.

The LLM focuses on comparing natural-language meaning. It does not need to rediscover a parent-child relationship that the application already knows or take responsibility for field-level structural consistency.

That small separation reduces the model’s job and makes the application more predictable.

A flattened two-level category taxonomy where a lightweight LLM selects one structured category key and deterministic code maps it to exact Level 1 and Level 2 values.
Instead of asking the LLM to preserve the hierarchy itself, let it select one valid leaf key and let deterministic application code map that key to the exact L1/L2 field combination.

5. I Changed the AI’s Job from “Make the Change” to “Propose the Change”

Even if the model concludes that the inquiry has clearly changed, it does not need to modify the Case immediately.

AI is useful for questions such as:

  • What does the recent conversation mean?
  • Is the customer still talking about the previous issue?
  • Has a genuinely new problem appeared?
  • Which valid Category best matches the current intent?
  • Why does the model think the intent changed?

There are other actions that the AI does not need to own directly:

  • Closing a Case or a previous handling segment
  • Changing the owner or Queue
  • Recording SLA boundaries
  • Writing operational history
  • Sending a customer notification

So I started treating the model output as a Transition Proposal rather than a State Change.

An agent-facing view might show:

Current Category
Billing

AI Proposal
Product Support → Device Failure

Reason
The customer explicitly says the billing issue is resolved and is now reporting a new device failure.

[Keep current type] [Accept change]

That is where the AI’s responsibility can stop.

The AI judges what appears to be happening. The system decides what that judgment is allowed to change.

6. Human Accept Became the Transaction Boundary

Who should commit the Transition Proposal?

For this use case, I would not introduce a separate AI operations role just to approve every change. The service agent already has the relevant context. They are reading the conversation and actually handling the Case.

That makes the agent’s Accept action more than a review button.

I treat it as the commit point where the business state is allowed to change.

AI Interpretation
        ↓
Transition Proposal
        ↓
Human Accept
        ↓
----------------------
Transaction Boundary
----------------------
        ↓
Deterministic Logic
        ↓
Category Update
Owner / Queue Update
History / Timestamp
Notification

A high model confidence does not skip that boundary.

And after the human accepts the transition, there is no reason to ask the LLM again whether the system should apply it. The business decision has already been made. From that point forward, the system should execute the committed state transition accurately.

This is slightly different from the generic idea that Human-in-the-loop simply means “a human checks because AI may be wrong.”

Human Accept is the transaction boundary where real authority to change business state is exercised.

Before that point, probabilistic interpretation is useful. After that point, I want the workflow to become as deterministic as possible.

7. Preserving the Previous Work Segment Exposed a More Practical Constraint

Once a Billing Case becomes Product Support, another question appears.

What should happen to the work the Billing team already performed?

If I were designing an ideal data model from scratch, I could separate Conversation and Business Case into different objects and model each handling segment cleanly.

Real customer environments rarely give that much freedom.

In this case, users were already working from the Case. The Case screen and Assignment structure had been built and maintained elsewhere. The customer was not asking for a new Case Management Platform.

The requirement was closer to:

“Make this capability work inside the environment we already have.”

Rebuilding the entire data model might produce a cleaner architecture diagram, but it could still be the wrong project decision.

One pragmatic option is to keep the original Case as the anchor for the Email Thread while preserving the previous handling segment as historical operational data when the Category transition is accepted.

For example:

Original Case
Billing
09:10 work starts
        ↓
10:03 Transition Accept
        ↓
Previous Billing handling
→ Closed historical record

Original Case
→ Product Support
→ New owning team
→ Email Thread continues

I would not present this as the universal Salesforce answer.

It is a pragmatic option under a specific constraint: preserve the existing Case-centric workflow and Email-to-Case behavior as much as possible.

Once again, the current system and the way people already work matter more than an abstractly perfect data model.

8. Record Creation Time and Actual Work Start Time Are Not the Same Thing

Preserving a historical handling segment creates another subtle problem.

Suppose a Historical Case or record is created at 10:03 when the transition is accepted.

That does not mean the Billing agent started working at 10:03.

The real sequence may be:

09:10 — Billing work starts
10:03 — Category Transition accepted

The handling time is 53 minutes.

If the historical record only carries a new CreatedDate of 10:03, later analytics can make that work appear to have taken zero minutes.

The system therefore needs to preserve timestamps that have business meaning, for example:

Category Started At
Transition Accepted At
First Pickup At
Resolved At

A record timestamp and the actual start of work can be different things.

Even if nobody is analyzing these fields today, recording the events from the beginning matters. Months later, we may want to know which Categories take longest to resolve, how much delay was caused by wrong routing, or where Category transitions happen repeatedly.

We cannot reconstruct those operational events reliably after the fact if we never captured them.

A Salesforce handling timeline showing why CreatedDate can differ from the actual work start and why Category Started At, Transition Accepted At, First Pickup At, and Resolved At should be recorded separately.
A newly created historical record may not reveal when the work actually began. Business timestamps need to preserve the start, transition, pickup, and resolution events required for later operational analysis.

This becomes especially important in Part 3, where the classification system starts learning from production outcomes rather than just model responses.

9. Splitting Business State Does Not Mean Rebuilding the Email Thread

Once we start separating handling segments, it is tempting to split the EmailMessages as well.

Keep the Billing emails on a Billing Case, move the Product Support messages to a new Case, and make the history look perfectly segmented.

The architecture becomes much more complicated the moment we do that.

Which Case should a reply to an older message belong to? What happens if the customer replies to an email from the previous segment? How do we reconstruct the technical thread for the next inbound message?

At that point, we are beginning to reimplement an area that Salesforce Email-to-Case already manages.

Splitting business state does not require splitting the technical thread in the same way.

For this scenario, I would preserve the existing Email-to-Case relationship unless there is a strong requirement to change it.

This is the same principle I reached in Part 1: keep using what the existing platform already does well.

Adding AI is not a reason to redraw every system boundary.

10. What If More Emails Arrive Before the Agent Accepts the Proposal?

One final edge case is very realistic.

The customer reports a device problem, and the AI proposes a transition to Product Support. But the assigned agent has not reviewed the proposal yet.

Then more messages arrive.

Email #5
“The device will not power on.”

AI
Product Support transition proposed

Still pending human review

Email #6
“I reconnected the power cable.”

Email #7
“The problem is still there. Please check it quickly.”

If every message creates a brand-new Transition Proposal, the workflow starts oscillating again at the proposal layer.

The model made three judgments, but operationally these messages may simply be three updates about one new issue.

If there is already a Pending Transition, a better design may be to attach new messages to that pending candidate and strengthen or revise its context rather than creating a fresh proposal each time.

Pending Transition
Product Support
    ├─ Email #5
    ├─ Email #6
    └─ Email #7

This is where concepts such as debounce, pending state, and sometimes hysteresis become relevant.

With unstructured events, preventing unnecessary state oscillation can matter as much as classification accuracy.

The timing of customer communication follows the same principle.

I would not notify the customer the moment the AI creates a proposal. A more natural sequence is:

AI Proposal
      ↓
Human Accept
      ↓
Committed Business State
      ↓
Customer Notification

The customer should receive the state the company has actually committed to, not an intermediate model inference.

11. In the End, I Separated What the LLM Is Good At from What the System Is Good At

This started as a requirement to read an email and set a Category.

Walking through real operating scenarios made the design more specific, but I did not want every new edge case to become another LLM capability.

What the LLM is good at

  • Interpreting natural language
  • Comparing recent context
  • Identifying current customer intent
  • Selecting a bounded Category candidate
  • Detecting a likely intent change
  • Summarizing the reason for that change

What application code and Salesforce are better at

  • Guaranteeing valid Category combinations
  • Mapping L1/L2 fields
  • Checking Case state
  • Enforcing permissions
  • Managing Transition state
  • Updating owner / Queue
  • Recording timestamps
  • Maintaining audit history
  • Sending downstream notifications

What the human owns

  • Accepting or rejecting a Transition in the real business context
  • Exercising authority to commit the business-state change

The architecture I prefer is therefore fairly simple.

Let the LLM interpret ambiguous meaning. Let the application own state, authority, consistency, and transactions.

Agents can technically do more and more, but that does not mean every operation should become agentic.

The opposite extreme is not attractive either. Trying to encode every possible expression of customer intent as deterministic rules leads to an endless rule-maintenance problem.

This is not a choice between AI and deterministic software.

It is a question of giving each one the job it is structurally better suited to perform.

Part 1 asked what judgment should be delegated to AI.

This article followed the next question: how should that judgment become a safe business-state transition?

Once this structure is running in production, it begins to generate a new kind of data.

What did the AI predict? Which transition did it propose? Did the human accept or reject it? Was the Category changed again later? When did an agent first pick it up? When did that handling segment end? Which patterns repeat?

That data can become much more than an operational log.

Part 3 looks at how to turn those outcomes into a Closed Loop: how to identify real misclassification, distinguish human correction from actual ground truth, evaluate candidate improvements, and use Pickup, Transition, and Resolution timestamps as part of the business evidence for whether the system is getting better.