← Tidelines/Best practices

Rewrite: the duty of care nothing can check

Every contact centre has a section about customers who need extra help, and it is the section written with the most care and the least specificity. The checker has one warning to offer, and it is not on either of the two lines that decide what the agent actually does.

by TypeGlish team8 min read#best-practices
Careful. Sensitive. Silent.

TL;DR A conditional consequence is not read as a rule: MUST be extra careful with a vulnerable customer is a prompt/unmeasurable warning at C (71/100), and IF a customer seems vulnerable THEN be extra careful is 0 error, 0 warning, 0 info at C (76/100), the same score as the same guard with a real bound after it. Keep the modal and move the trigger into the subject: MUST reply in at most 3 sentences to a customer who states a support signal is B (87/100) with enforceability 100, and it takes the section from C (66/100) to A (97/100).

Kestrel Energy supplies gas and electricity to about 900,000 homes, and its chat agent handles the meter readings, the direct debits, and the bills nobody can pay. The vulnerable-customer section of that prompt was written by the head of customer care, personally, after a training day. It is five lines long. It is the most carefully worded part of the file, and it is the part with the least in it that anything downstream can act on: not the model, not the checker, not the QA team reading transcripts on Monday.

§1The before

Here is the section as it ships, with the Role line above it for context. Read it the way a reviewer would: five statements, all of them things you would agree with.

care.tg - before✗ C (66/100)
# Role
You are a chat support agent for Kestrel Energy, a British energy supplier.

# Vulnerable customers
- IF a customer seems vulnerable THEN be extra careful.
- ALWAYS be sensitive with vulnerable customers.
- MUST offer the priority services register where appropriate.
- Vulnerable customers should be handled with care by the agent.
- IF the customer is in a bad situation THEN escalate to the specialist team quickly.

Now the checker, and then the same file under --strict, which is where a nervous author goes looking for reassurance.

tg check, --strict and score - care.tg✗ nothing on lines 5 or 9
$ typeglish check care.tg
care.tg:6:1   warn   prompt/unmeasurable  Unmeasurable rule - no observable action or bound,
  so nothing can check compliance. Name a concrete action ("cite the source", "at most 3
  sentences") or move it to a prose block.
care.tg:7:45  info   prompt/vague  Vague - "where appropriate" names a judgment call without
  the criterion to judge by, so nothing can check it. Replace it with a measurable form
  ("at most 3 sentences", "within 24 hours", "cite the source").
care.tg:8:1   info   prompt/agentless-passive  The subject is not the doer (passive). If the
  by-phrase names the doer, put the doer first.

 1 file - 0 error, 1 warning, 2 info

$ typeglish check care.tg --strict
 1 file - 0 error, 1 warning, 2 info

$ typeglish score care.tg
care.tg - C (66/100)  proven errors: none  tiers: base+z3
  planes  runtime 71 (what the model reads) · hygiene 50 (source only)
  facets  enforceability 48 x.21 · hardness 73 x.12 · directness 85 x.08
          consistency 100 x.17 · structure 100 x.12 · annotation 0 x.12
          style 25 x.08 · security 100 x.08
  lever   annotation 0/100 (up to +12 overall)
Three findings, all of them on lines 6, 7 and 8. Lines 5 and 9, the two that carry the trigger and the escalation, draw nothing. --strict escalates none of it, because a warning about vagueness is not a correctness defect and there is no correctness defect here to find.

That is the whole problem in one output. The file builds, it exits 0, and a CI gate set at --min C passes it. The two lines a duty of care actually turns on are the two the toolchain has no opinion about.

§2The frame that switches a rule off

Line 6 and line 5 say the same thing. ALWAYS be sensitive with vulnerable customers is a warning. IF a customer seems vulnerable THEN be extra careful is silent. The difference is not the wording of the instruction, it is what surrounds it: a modal directive is a rule and gets read as one, and the consequence of a prose conditional is not.

tg check and score - nine ways to ask for care✗ the five silent rows score highest
  the line                                                     check                    score
  MUST be extra careful with a vulnerable customer.            warn  unmeasurable       C (71/100)
  ALWAYS be sensitive with vulnerable customers.               warn  unmeasurable       C (71/100)
  MUST take extra care where appropriate.                      info  vague              C (68/100)
  Vulnerable customers should be handled with care by ...      info  agentless-passive  D (64/100)

  IF a customer seems vulnerable THEN be extra careful.        clean                    C (76/100)
  WHEN a customer is vulnerable THEN take extra care.          clean                    C (75/100)
  IF a customer seems vulnerable THEN reply in at most 3 ...   clean                    C (76/100)
  MUST handle vulnerable customers with care.                  clean                    B (81/100)
  MUST use your best judgment with a vulnerable customer.      clean                    B (81/100)

  MUST reply in at most 3 sentences to a customer who          clean                    B (87/100)
    states a support signal.
Every row is the same three-line file with one rule swapped. The two emptiest sentences in the table, handle with care and use your best judgment, are clean at B (81/100) with enforceability 70, because handle and use are catalog verbs and the line parses as a directive that does something. The last row is the same policy as row 7 with the trigger moved into the subject: enforceability 100.

The pair worth staring at is rows 5 and 7. IF a customer seems vulnerable THEN be extra careful and IF a customer seems vulnerable THEN reply in at most 3 sentences are byte-identical in the score report: C (76/100), enforceability 50, directness 90. One of them is a bound a transcript can settle and one of them is a feeling, and from outside the frame they are indistinguishable, because the frame is what got measured.

A qualifier does not weaken a rule. It moves the rule somewhere nothing is looking.

This is the same mechanism you did not narrow that rule, you moved it takes apart at length, arriving from the other direction. There the scope phrase relocated a claim out of a proof. Here the conditional relocates a whole instruction out of the graded set. And it is worth being clear that the checker is not wrong: a prose IF is a statement the model weighs at runtime, not an obligation the document carries, so grading its consequence as a standing rule would be the actual error. The cost is that the frame your policy team reaches for by instinct is the one frame that turns the analysis off.

§3The guard decides what the rest of the line gets

It goes further than the consequence. The definite reference in line 9, the specialist team, is a lookup instruction pointed at a team this document never introduces, and on its own that is a reported finding. Behind the right guard it is not.

tg check - one escalation, four frames✗ one of four is silent
  the line                                                          check                       score
  MUST escalate the customer to the specialist team quickly.        info unintroduced-definite  B (80/100)
  IF a customer mentions a disability THEN escalate to the ...      info unintroduced-definite  C (70/100)
  IF a customer seems vulnerable THEN escalate to the ...           info unintroduced-definite  C (70/100)
  IF a customer is vulnerable THEN escalate to the ...              clean                       C (75/100)

$ typeglish check y2.tg
y2.tg:5:1  info  prompt/unintroduced-definite  "the specialist team" retrieves something this
  document never introduces - a model must guess which team is meant. Introduce it on
  another line ("You manage a team.") or name it outright.
Three guards you would call equivalent in a review, and the copula one takes the consequence off the report entirely. Seems vulnerable is reported, is vulnerable is not, and the row that goes quiet is the row with the better score. This is the narrowest boundary in the section, and it is exactly the shape of line 9 in the file that shipped.

Which brings up the other half of the problem, the half no compiler is going to solve for you. Seems vulnerable and is in a bad situation are not underspecified rules. They are not rules at all: they are the name of a decision, handed to a model that has met this customer eleven seconds ago and has no case history, no account flags, and no colleague to ask. The word vulnerable is in the checker's vocabulary, so The customer IS vulnerable. compiles without complaint, and that is the correct behaviour and completely unhelpful, because what the word means at Kestrel Energy is a list that lives in a training deck.

§4Write down what counts, then what changes

The rewrite is two moves, and neither of them is a policy change. First, the trigger stops being a judgment and becomes a set of things a customer can actually say, declared once, in the one place a new signal gets added. Second, every consequence becomes a modal rule with the trigger in the subject, so the rule is a rule and the bound is a bound.

Note what the second move is not: it is not deleting the conditionals for style points. It is the difference between four lines the toolchain reads and four lines it skips. Written as guards, the same four rules score A (91/100) with enforceability 63, and typeglish test --dry reports coverage: 0/1 rules exercised for the whole file, because the conditional lines are not counted as rules to cover.

care.tg - after✓ A (97/100)
<$CONFIG>
  $IMPORT tool add_to_priority_services
</$CONFIG>

# Role
@@ role: the desk this file speaks for, and the owner of every rule below
You are a chat support agent for Kestrel Energy, a British energy supplier.
@@ desk: the destination the escalation rule needs, introduced before it is used
The %specialist support team% IS a desk for customers who need extra help.

# Support needs
@@ signals: the one list a new signal is added to - no rule below guesses at this
Your support signals INCLUDING a disclosed disability, a mention of a mental health condition, a recent bereavement, a stated difficulty with reading.
@@ pace: what "be extra careful" was asking for, as a bound a transcript can settle
- MUST reply in at most 3 sentences to a customer who states a support signal.
@@ psr: the register is an action with a tool behind it, not a leaflet to mention
- MUST offer the priority services register with @[add_to_priority_services] to a customer who states a support signal.
@@ no_sales: the sales rule everybody assumes and nobody writes down
- NEVER mention a tariff upgrade to a customer who states a support signal.
@@ escalate: the one signal that is not a support need but an emergency
- MUST escalate a customer who mentions self-harm to the %specialist support team%.

$TEST bereavement
  - input:: My husband died last month and I need to change the name on the account.
  - expect::
    - contains "priority services"
    - at most 3 sentences
The signals list is a declaration, not a rule, and it is the only line anybody edits when the care team adds a fourteenth signal. %specialist support team% is a name literal: three words bound as one name, because an unquoted multi-word definite binds nothing and the sigils strip on compile.
tg check, score, test --dry and build - care.tg after✓ 0 error, 0 warning, 0 info
$ typeglish check care.tg
 1 file - 0 error, 0 warning, 0 info

$ typeglish score care.tg
care.tg - A (97/100)  proven errors: none  tiers: base+z3
  planes  runtime 96 (what the model reads) · hygiene 100 (source only)
  facets  enforceability 85 x.21 · hardness 100 x.12 · directness 97 x.08
          consistency 100 x.17 · structure 100 x.12 · annotation 100 x.12
          style 100 x.08 · security 100 x.08
  lever   enforceability 85/100 (up to +3 overall)

$ typeglish test care.tg --dry
 care.tg  coverage: 1/4 rules exercised
  · bereavement - "My husband died last month and I need to change the name on " (not run)
       contains "priority services"
       at most 3 sentences
 1 prompt - 0 failed

$ typeglish build care.tg
 built .typeglish/dist/care.txt ← care.tg (327dfba51537, full)
coverage: 1/4 is the honest number and the point of the exercise: the file now has four rules to cover, where the guarded version had one. The suite validates offline and the contains assert only settles against a model, so the register is pinned in CI, not proven there.

What the model actually receives is the compiled artifact, with the scaffolding gone and the name literal stripped. The pace rule and the sales rule arrive as flat obligations with their own subjects, which is the shape that survives being read once, quickly, in the middle of a long conversation.

.typeglish/dist/care.txt - what the model reads
# Role
You are a chat support agent for Kestrel Energy, a British energy supplier. The specialist
support team IS a desk for customers who need extra help.

# Support needs
Your support signals INCLUDING a disclosed disability, a mention of a mental health
condition, a recent bereavement, a stated difficulty with reading.
- MUST reply in at most 3 sentences to a customer who states a support signal.
- MUST offer the priority services register with add_to_priority_services to a customer
  who states a support signal.
- NEVER mention a tariff upgrade to a customer who states a support signal.
- MUST escalate a customer who mentions self-harm to the specialist support team.
The NEVER mention a tariff upgrade line was never in the original section. Nobody had written it down, because everybody knew it.

§5What this does not fix

Three honest limits, because a duty of care is not a scoring exercise.

  • The list is still yours. Nothing in the toolchain knows that a bereavement belongs on it and a late payment does not. What the rewrite buys is that the list is one line in one file, rather than an adjective distributed across five.
  • Nothing links the rules to the list. a customer who states a support signal is prose that happens to use the same words as the declaration above it. The checker does not prove that connection, and if you rename the list nothing will tell you. Put them adjacent, so a second author has to walk past the inventory.
  • The score would have let you ship the empty version. MUST use your best judgment with a vulnerable customer is B (81/100) and clean, which is the whole subject of the sentence that repeals the rest of your prompt. Grades measure how a rule is written, not whether it means anything, and a section like this one is exactly where that gap is widest.

The habit that actually holds: for every rule in a care section, ask what a QA reviewer would highlight in the transcript to say the rule was followed. If there is nothing to highlight, the rule is a value, not an instruction, and it belongs in a prose block where it is honest about that. Introducing the destination first is the other half, and that is the same lesson as the policy doc somebody pasted into your agent: a definite article is a lookup, and a model that cannot resolve it will resolve it from its own priors.

§6Common questions

Why does my AI agent ignore the rule about vulnerable customers?
Because the rule usually names a judgment on both ends and neither end reaches the model as something it can act on. IF a customer seems vulnerable THEN be extra careful is 0 error, 0 warning, 0 info at C (76/100): the trigger is a state nobody defined and the consequence is a quality with no observable behaviour attached. Give the trigger a list of signals the customer can actually state, and give the consequence a bound a transcript can settle, such as at most 3 sentences or a tool call.
Does IF ... THEN work in a system prompt?
It works on the model and it costs you the checks. In TypeGlish a prose conditional is a statement the model weighs, and the consequence after THEN is not analysed as a rule: MUST be extra careful with a vulnerable customer is a prompt/unmeasurable warning at C (71/100), and the same words behind a guard are silent. The score reads the frame rather than the consequence, so IF a customer seems vulnerable THEN be extra careful and IF a customer seems vulnerable THEN reply in at most 3 sentences are both C (76/100) with enforceability 50. Keep the modal and move the trigger into the subject instead: MUST reply in at most 3 sentences to a customer who states a support signal is B (87/100) with enforceability 100.
How do I write a vulnerable customer rule an AI agent can follow?
Write down what counts, then write down what changes. Declare the signals once as a list the file owns, then attach one modal rule per behaviour change: a pace bound, a tool call that puts the customer on the priority services register, a prohibition on selling, and a named destination for the one signal that is an emergency rather than a support need. The section in this post goes from C (66/100) to A (97/100) that way, with 0 error, 0 warning, 0 info and enforceability 48 to 85, and no policy changed.
What does prompt/unmeasurable mean in TypeGlish?
It is a warning that a rule names no observable action or bound, so nothing can check compliance. The message asks for a concrete action such as cite the source or a bound such as at most 3 sentences, or for the line to move into a prose block where it is not read as a rule at all. It fires on ALWAYS be sensitive with vulnerable customers and on MUST be extra careful with a vulnerable customer, and it does not fire on either of those consequences behind an IF.
Field note

The reason this section resists editing is that it is the one part of the prompt with a moral weight attached to the wording. Somebody chose sensitive over careful in a meeting. Proposing at most 3 sentences in its place sounds like replacing compassion with a character limit, and in a review that argument wins. It helps to put the two documents side by side: the care policy, which is for humans and should say be sensitive, and the prompt, which is a spec for a system that cannot feel anything and can only be told what to do differently. The rewrite is not a smaller commitment. It is the same commitment written in the only vocabulary the reader has.

∿ washed up Sep 14, 2026 ∿