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.
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.
# 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.
$ 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)
--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.
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.
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.
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.
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.
<$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
%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.$ 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.
# 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.
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 signalis 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 customerisB (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 carefulis0 error, 0 warning, 0 infoatC (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 customeris aprompt/unmeasurablewarning atC (71/100), and the same words behind a guard are silent. The score reads the frame rather than the consequence, soIF a customer seems vulnerable THEN be extra carefulandIF a customer seems vulnerable THEN reply in at most 3 sentencesare bothC (76/100)withenforceability 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 signalisB (87/100)withenforceability 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)toA (97/100)that way, with0 error, 0 warning, 0 infoandenforceability48 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 customersand onMUST be extra careful with a vulnerable customer, and it does not fire on either of those consequences behind anIF.
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.