Spam or duplicate detect Jev pattern
Two Nouls: is this a duplicate of recent tickets, and is it spam?

Duplicates and spam are different failure modes. A furious customer who emails twice is not spam. A crypto pump in the support form is not a duplicate. Pass recent tickets in state so “duplicate” has something to duplicate.
This spam or duplicate detect schema is a paste-ready TypeSafe Jev request for jev-latest. Copy the JSON, keep thresholds in your code, and calibrate on your labels. Jev Patterns is independent and not affiliated with TypeSafe AI.
Use spam or duplicate detect when
- A shared inbox receives repeats from the same address or subject.
- You want to suppress spam without burying real follow-ups.
- Deduping is currently a 24-hour human ritual.
Do not use spam or duplicate detect when
- You only have the new message and no prior tickets in state.
- You need near-duplicate hashing of attachments or images.
- The action is to merge tickets — do that in your system of record.
Confidence thresholds for spam or duplicate detect
Keep these in your code. They are not part of the model call.
| When | Action |
|---|---|
| is_spam.noul >= 0.85 | Reject. Do not open a ticket |
| is_duplicate.noul >= 0.80 && is_spam.noul < 0.30 | Attach to the existing ticket; do not re-route |
| both below 0.50 | Create a new ticket |
Pass examples
Third email, same outage
Duplicate, not spam. Attach it.
{
"incoming": {
"body": "Still blocked. Third email."
},
"recent_from_sender": [
{
"body": "Payouts failing since Monday."
}
]
}New issue from same person
Not a duplicate. New ticket.
{
"incoming": {
"body": "Separately, our SSO metadata expired."
},
"recent_from_sender": [
{
"body": "Payouts failing since Monday."
}
]
}Blast
Spam. Duplicate is near 0 because there is nothing to duplicate.
{
"incoming": {
"body": "Congratulations you have won a grant. Wire details here."
},
"recent_from_sender": []
}Ambiguous examples
Same theme, new error code
Material update. Duplicate should not be automatic.
{
"incoming": {
"body": "Now seeing error PAYOUT_TAX_ID on the same transfers."
},
"recent_from_sender": [
{
"body": "Payouts failing since Monday."
}
]
}CC'd thread
Could be duplicate noise. Put participants in state.
{
"incoming": {
"body": "Adding Dana. See below."
},
"recent_from_sender": [
{
"body": "Long thread…"
}
]
}No history passed
You cannot detect duplicates without the prior tickets.
{
"incoming": {
"body": "Following up"
},
"recent_from_sender": []
}The problem spam or duplicate detect is for
Support and CRM piles fill with the same outage pasted six times and with SEO garbage that only looks like a ticket. A single “is this junk” classifier collapses two jobs. Duplicate is a merge. Spam is a drop. Spam or duplicate detect keeps them as two Nouls.
Near-duplicate detection in search uses Jaccard or embeddings. You can still run those. This pattern is for the case where the second ticket is a paraphrase from a tired customer, or a newsletter that mentions your brand. You pass the new text and the likely original; Jev answers is_duplicate and is_spam.
Do not use spam or duplicate detect to write “we already have this.” Merge in the ticket system. Tell the customer with a template.
Why this spam or duplicate detect schema uses Jev
is_duplicate needs the candidate original in state. Without it, the Noul is “does this sound like a repeat,” which is weaker. is_spam can run on the new text alone.
Independent Nouls: a duplicate of a real outage is not spam. Spam that happens to repeat is both. Your code should merge versus drop on those bits separately.
Pair with support ticket routing. There is no reason to route spam you are about to drop, except as a cheap second look.
What to put in state for spam or duplicate detect
new_ticket, recent_ticket (id, subject, body, created_at), and signup or IP reputation if you have it. Spam or duplicate detect cannot query Elasticsearch for you. You pick the candidate.
Pass channel. Twitter @mentions and email have different spam priors. Put that in state, not in a lecture in instructions.
If you already have an embedding duplicate score, pass it as a number. Jev can use it as a feature of state; it will not recompute cosine.
How to wire spam or duplicate detect in code
is_spam.noul >= 0.85 → drop or quarantine. is_duplicate.noul >= 0.80 → merge into recent_ticket.id. If both are middling, human. If both are low, create a new ticket and continue to routing.
Never auto-merge across customers. Include account_id in the candidate so a similar outage report from another company stays separate.
Audit the drop folder weekly. Spam or duplicate detect will err. The cost of a dropped real ticket is higher than an extra merge review.
Eval plan: for duplicates, you need pairs, not singles. Build a set of known merges and known distinct outage reports from two companies. Spam or duplicate detect should split those. If it merges across account_id, your state is missing the id.
Failure modes
No candidate original
Then is_duplicate is a vibe. Fetch a candidate first, or skip that Noul.
One Choice spam|dup|fresh
A ticket can be both spam and a duplicate of spam. Two Nouls in spam or duplicate detect allow that.
Auto-reply on merge
Jev will not write “closing as duplicate.” Your template will.
Copy, run, calibrate
The JSON in the rail is the spam or duplicate detect request for jev-latest. Copy it into your stack, or open Spam or duplicate detect in Jev Studio and draw the fixture bars. Thresholds stay in your repository. Calibrate on your labels before you auto-apply. Official model docs live at docs.typesafe.ai. Jev Patterns is independent and not affiliated with TypeSafe AI.
Related reading: Choice, Score, Noul, confidence thresholds, when not to use Jev.
Spam or duplicate detect: FAQ
- What is spam or duplicate detect in Jev Patterns?
- Spam or duplicate detect is two Nouls, is_duplicate and is_spam, run on a new ticket plus an optional candidate original. Your code merges or drops.
- Do I still need embeddings for spam or duplicate detect?
- They help you pick the candidate original. The Jev Noul judges the pair. They are complementary.
- Can spam or duplicate detect see my whole corpus?
- No. You retrieve a candidate and put it in state. Jev does not search your store.
- What threshold should drop spam?
- Start at is_spam.noul >= 0.85 and review misses. Lower only if the quarantine queue is drowning you.
- Is spam or duplicate detect a moderation API?
- It is a starting schema on TypeSafe Jev, independent of hosted moderation vendors. Not affiliated with TypeSafe AI.
Last reviewed 21 September 2026. Independent of TypeSafe AI.
Next
Related Jev Patterns

Moderation
Content moderation screen
Run independent Nouls for spam, harassment, sexual content, self-harm, and malware.

Support
Support ticket routing
Send a ticket to the right department and flag whether it should jump the queue.

Support
Escalate to human
A single Noul: should a person take this over from the bot or the junior queue?

Studio
Run Spam or duplicate detect in Studio
Fixture bars first. Optional live call stays in this browser.