← Tidelines/Best practices

A product recall just landed in the prompt

Somebody forwards the recall notice with “can we get this into the bot today?”, and the fastest fix is to paste it under the rules. The paragraph tells customers what to do. It tells the agent almost nothing, and it quietly overrules a rule that is still there.

by TypeGlish team7 min read#best-practices
Stop using it. Then what?

TL;DR When a product recall reaches your support agent, do not paste the notice: rewrite it as rules the agent performs, give the recall remedy its own tool so it never fights your refund rules, let a lookup decide which products are affected, and test the recalled-product contact end to end.

Hallam Home sells homeware online, and its chat assistant, Wren, handles orders, returns and the odd broken toaster. On Monday morning the safety team confirms a recall: the Glide 1.7L kettle, model HK-17, has a base that can overheat. The notice goes to the website, the email list and the support channel. Here are the eight checks for the pull request that puts it in front of Wren.

§1The paragraph from the notice

wren-patched.tg - the standing prompt, plus the recall as it arrived✗ logic/contradiction
$TOOL open_return
  - description:: Open a return for an order.
  - input::
    - order_id:: string: the order to return.

# Role
You are Wren, the support assistant for Hallam Home, an online homeware shop.

# Constraints
- MUST keep every reply to at most 4 sentences.
- NEVER offer a refund.
- WHEN a customer asks for a refund THEN MUST call @[open_return].

# Product recall
IMPORTANT: The Glide 1.7L kettle (model HK-17) is being recalled because the base can overheat. Customers should stop using it straight away. Make sure any injury is taken seriously.
- IF the customer owns a recalled kettle THEN MUST offer a refund.
Everything above # Product recall is the prompt that shipped last quarter. The recall section is the notice, lightly trimmed, plus the one rule somebody wrote from it.
tg check - wren-patched.tg✗ build refused
$ typeglish check wren-patched.tg
wren-patched.tg:11:1  error  logic/contradiction  Conflicts with line 16. Logical conflict — "offer a refund" is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...).
                 ↳ line 16: - IF the customer owns a recalled kettle THEN MUST offer a refund.
wren-patched.tg:15:1  info   prompt/unintroduced-definite  "The Glide" retrieves something this document never introduces - a model must guess which Glide is meant. Mention a Glide on an earlier line, or anchor it here ("their Glide", "the Glide you ...").
wren-patched.tg:15:1  info   prompt/unintroduced-definite  "the base" retrieves something this document never introduces - a model must guess which base is meant. Mention a base on an earlier line, or anchor it here ("their base", "the base you ...").
wren-patched.tg:15:1  info   prompt/agentless-passive  The doer is deleted (agentless passive) - who performs this? Name the actor or use the imperative: "Verify the order." instead of "The order is verified."
wren-patched.tg:16:1  error  logic/contradiction  Conflicts with line 11. Logical conflict — "offer a refund" is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...).
                 ↳ line 11: - NEVER offer a refund.

✗ 1 file — 2 error, 0 warning, 3 info

Check 1: rewrite the notice as things the agent does. Read the pasted paragraph from Wren’s side. Customers should stop using it straight away is a sentence about customers. It is the most important line in the recall, and nothing in it says Wren tells anybody anything. Make sure any injury is taken seriously names no actor and no action. The checker’s notes on line 15 are style notes (a passive, two things it never introduced), and the IMPORTANT: label changes nothing; How to mark a rule as important in an agent prompt covers why. Turn each sentence into a rule with Wren as the doer and a verb that can be checked: tell the customer to stop using the kettle, escalate an injury to a person.

Check 2: find the rule the recall overrules. Wren has never been allowed to offer a refund; ordinary refund requests open a return through a tool, and the returns team decides. The recall says a refund is owed. Those two lines share one action, offer a refund, one required and one forbidden, and the checker refuses the build: the grade is capped at F (64/100) until somebody decides. Without the checker, both lines reach the model in every conversation about a kettle.

The fix is not to delete the ban, because the ban is still right for the toaster. The recall remedy is a different process with a different owner, so give it a different action: a $TOOL open_recall_return that carries the full refund, and a recall rule that calls it. The ban on offering refunds stays true, and the recall rule never meets it. Bake-off: forbid the tool vs. never hand it over makes the general case for putting the money behind a tool.

A recall notice is written for the customer. The prompt needs the version written for the person answering the phone.

§2The model number decides

Check 3: do not let the agent decide what is recalled. Recalls are scoped: one model, often specific batches, and the list changes as the investigation goes on. A customer who says “the silver Hallam kettle” may own an HK-17 or one of three kettles that are fine. Put the affected list behind a lookup, $TOOL check_recall, ask for the model number printed under the base, and make the lookup’s answer the condition every recall rule hangs from. The prompt keeps one plain fact in # Context, which model and why, so Wren can explain the recall without inventing the details.

Check 4: put the safety instruction first. When the lookup matches, the first thing the customer hears is to stop using the kettle, before the return, the refund or an apology. That is one rule, written with Wren as the doer: IF the recall check matches THEN MUST tell the customer to stop using the kettle.

Check 5: never say a kettle is safe. The customer whose kettle is not on the list will ask whether it is safe, and the agent cannot inspect a kettle. Ban the claim. Our first draft, NEVER call a kettle safe., read as a rule the checker could not prove; NEVER describe a kettle as safe. reads clean. If the wording matters for liability, it matters enough to be provable.

Check 6: route every injury to a person. A burn, a scald, a damaged worktop: none of these is a chat to resolve. IF the customer reports an injury THEN escalate to a human agent. uses the catalog verb the checker knows, so the escalation is a rule it reads rather than a sentiment. How to write escalation rules for an AI support agent covers the handover itself.

§3The overlap the checker cannot see

Check 7: write down which rule wins on a recalled kettle with a fault. Wren has a standing rule to offer troubleshooting steps when a customer reports a fault, because most faults are a setting or a descaling job. A customer whose HK-17 “gets really hot underneath” is reporting a fault. The recall says nobody troubleshoots that kettle. So the recall section needs a rule that says so, and it is worth knowing what the checker does with it.

overlap.tg - the standing fault rule and the recall exception✓ clean
You are Wren, the support assistant for Hallam Home.

# Constraints
- IF the customer reports a fault THEN MUST offer troubleshooting steps.
- IF the recall check matches THEN NEVER offer troubleshooting steps.
tg check - the exception, guarded and unguarded✗ only the unguarded one is caught
$ typeglish check overlap.tg
✓ 1 file — 0 error, 0 warning, 0 info

$ typeglish check overlap2.tg
overlap2.tg:4:1  error  logic/contradiction  Conflicts with line 5. Logical conflict — "offer troubleshooting steps" is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...).
             ↳ line 5: - NEVER offer troubleshooting steps.
overlap2.tg:5:1  error  logic/contradiction  Conflicts with line 4. Logical conflict — "offer troubleshooting steps" is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...).
             ↳ line 4: - IF the customer reports a fault THEN MUST offer troubleshooting steps.

✗ 1 file — 2 error, 0 warning, 0 info
overlap2.tg is the same file with the condition dropped from the second rule. Unguarded, the ban covers every case and the checker proves the conflict. Guarded, it does not.

That green is accurate about what the checker can prove and silent about what it cannot. The two conditions are free text: the checker has no way to know that a customer with a recall match is also a customer reporting a fault, so it reads them as separate cases. They are the same case for every HK-17 owner who calls about the heat. Keep the exception explicit, and pin it with a test whose input is exactly that customer. How to write change-of-address rules for an AI support agent runs into the same limit with a dispatched order.

wren.tg - the recall, as rules, tools and tests✓ A (99/100)
$TOOL open_return
  - description:: Open a standard return for an order.
  - input::
    - order_id:: string: the order to return.

$TOOL check_recall
  - description:: Check a model number against the open product recalls.
  - input::
    - model_number:: string: the model number printed under the base.

$TOOL open_recall_return
  - description:: Open a recall return, with a full refund, for a recalled product.
  - input::
    - model_number:: string: the recalled model number.

# Role
@@ role: one sentence names the speaker, so every later "you" is the agent
You are Wren, the support assistant for Hallam Home, an online homeware shop.

# Context
@@ recall_fact: the facts the agent repeats to the customer, stated once
Hallam Home is recalling its Glide 1.7L kettle, model HK-17, because its base can overheat.

# Constraints
@@ brevity: a recall reply is a safety message, and short ones get read
- MUST keep every reply to at most 4 sentences.
@@ no_refund_offers: refunds go through a tool, never a promise in chat
- NEVER offer a refund.
@@ standard_returns: ordinary refund requests open a standard return
- WHEN a customer asks for a refund THEN MUST call @[open_return].
@@ fault_help: most faults are a setting or a descaling job
- IF the customer reports a fault THEN MUST offer troubleshooting steps.
@@ check_first: the model number decides, not the customer's description
- WHEN a customer mentions a kettle THEN MUST call @[check_recall].
@@ stop_using: the safety instruction comes before anything else
- IF the recall check matches THEN MUST tell the customer to stop using the kettle.
@@ no_fixes: a recalled kettle is not repaired over chat
- IF the recall check matches THEN NEVER offer troubleshooting steps.
@@ recall_return: the recall remedy has its own tool, so it never meets the refund ban
- IF the recall check matches THEN MUST call @[open_recall_return].
@@ no_safety_claims: the agent cannot inspect a kettle
- NEVER describe a kettle as safe.
@@ injury: an injury report is a person's call, not the bot's
- IF the customer reports an injury THEN escalate to a human agent.

$TEST hot_base
  - input:: My Glide kettle, HK-17, gets really hot underneath. How do I fix it?
  - expect::
    - contains "stop using"
    - at most 4 sentences
    - matches /^(?![\s\S]*safe to use)/
    - calls check_recall
    - does not offer troubleshooting steps
    - calls open_recall_return

$TEST burn
  - input:: I burned my hand on the kettle base this morning.
  - expect::
    - escalates to a human agent

$TEST toaster_refund
  - input:: The toaster I bought last week has stopped working. Can I get a refund?
  - expect::
    - calls open_return
    - offers troubleshooting steps for the toaster
    - does not offer a refund in the reply
The refund ban, the standard return and the fault rule are unchanged from the shipped prompt. Everything the recall adds is a lookup, a tool, and rules that hang from the lookup’s answer.

§4Test the recall contact

Check 8: test the recalled kettle, the injury, and the toaster. Three cases cover the change. hot_base is the overlap from §3: a recalled model reporting a fault, which must hear “stop using”, get no troubleshooting steps and no claim that the kettle is safe to use, and leave with a recall return open. burn is the injury path. toaster_refund is the regression test: an ordinary product still gets troubleshooting and a standard return, and still no refund promise in chat, which is how you know the recall did not leak into every conversation.

tg check, score and test --dry - wren.tg✓ 10/10 rules exercised
$ typeglish check wren.tg
✓ 1 file — 0 error, 0 warning, 0 info

$ typeglish score wren.tg
wren.tg — A (99/100)  proven errors: none  tiers: base+z3
  planes  runtime 99 (what the model reads) · hygiene 100 (source only)
  facets  enforceability 100 x.21 · hardness 100 x.12 · directness 93 x.08 · consistency 100 x.17 · structure 100 x.12 (hygiene) · annotation 100 x.12 (hygiene) · style 100 x.08 · security 100 x.08
  rules   10 of 10 rule-shaped lines read · 10/10 covered by $TEST

$ typeglish test wren.tg --dry
✓ wren.tg  coverage: 10/10 rules exercised
  · hot_base — "My Glide kettle, HK-17, gets really hot underneath. How do I" (not run)
      ✓ contains "stop using"
      ✓ at most 4 sentences
      ✓ matches /^(?![\s\S]*safe to use)/
      · rubric — 3 prose expectations, judged on a live run (needs ANTHROPIC_API_KEY)
  · burn — "I burned my hand on the kettle base this morning." (not run)
      · rubric — 1 prose expectation, judged on a live run (needs ANTHROPIC_API_KEY)
  · toaster_refund — "The toaster I bought last week has stopped working. Can I ge" (not run)
      · rubric — 3 prose expectations, judged on a live run (needs ANTHROPIC_API_KEY)
✓ 1 prompt — 0 failed
The contains, matches and sentence-count asserts run on every reply with no model judging them. The prose expectations, such as calling the right tool, are judged on a live run.

The negative lookahead is the one to keep. matches /^(?![\s\S]*safe to use)/ passes only when the phrase appears nowhere in the reply, so the day someone softens the safety ban, the test catches the reply that says it.

§5Common questions

How do I add a product recall to my AI support agent's prompt?
Do not paste the recall notice. Rewrite it as rules the agent can act on: call a lookup tool with the model number, tell the customer to stop using the product when the lookup matches, open the recall return with its own tool, and escalate any injury to a person. Keep the list of affected models in the lookup, not in the prompt.
Why does my chatbot keep troubleshooting a recalled product?
Because the standing rule that tells it to troubleshoot faults still fires, and nothing in the prompt says the recall wins. Write the exception as its own rule, IF the recall check matches THEN NEVER offer troubleshooting steps, and pin it with a test whose input is a recalled model with a fault. A checker cannot prove that two differently worded conditions overlap, so the test is what holds it.
Should an AI agent decide whether a customer's product is part of a recall?
No. Recalls are usually scoped to specific models or batches, and the customer's description of the product is not reliable enough to decide on. Ask for the model number, call a recall lookup with it, and let the lookup's answer decide which path the conversation takes.
Can TypeGlish tell when a recall rule conflicts with my refund policy?
When the two rules share an action, yes. A standing NEVER offer a refund beside a recall line that says MUST offer a refund is a proven logic/contradiction, and the build is refused. If the two rules sit behind different conditions, such as a fault report and a recall match, the checker treats them as separate cases, so write the precedence down and test it.
Field note

A recall changes faster than most prompt content: batches get added, the remedy changes, the notice eventually closes. Every one of those changes should land in the check_recall lookup, not the prompt, which is why the prompt names only the model and the reason. When the prompt itself does change, ship it as its own pull request and its own build; typeglish build wren.tg wrote this one as 2374881a7dea, and a hash per wording is how you answer “what was the bot saying on Tuesday?”

∿ washed up Oct 20, 2026 ∿