Skip to content
OpsNOUL

Spam or duplicate detect Jev pattern

Two Nouls: is this a duplicate of recent tickets, and is it spam?

Two identical letters, one stamped duplicate, a spam pad beside them
Duplicate and spam are different Nouls.

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.

WhenAction
is_spam.noul >= 0.85Reject. Do not open a ticket
is_duplicate.noul >= 0.80 && is_spam.noul < 0.30Attach to the existing ticket; do not re-route
both below 0.50Create 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.