← Tidelines/Teardowns

Teardown: nobody checked the Spanish one

Six rules for an energy retailer's support agent, run through the same localization pipeline that handles the marketing site. The Spanish file is cleaner than the English one: zero findings against one. It is cleaner because there is nothing left in it to be wrong about.

by TypeGlish team9 min read#teardowns
Six rules. Zero rules.

TL;DR A translated system prompt has no rules in it: the Spanish version of a six-rule support prompt is 0 error, 0 warning, 0 info at C (76/100) with enforceability 50 and coverage: 0/0 rules exercised, where the English original is 0 error, 0 warning, 1 info at B (85/100) with enforceability 95 and coverage: 1/6. Every operator in TypeGlish is an English word, so DEBES is not MUST and a translated rule classifies as prose. Keep the rules and the role line in English, make the reply language a rule of its own, and put the localized customer-facing copy in a quoted literal zone.

Localization is the least controversial system in a midmarket CX org. Somebody writes English, a pipeline produces Spanish, Portuguese and Polish, a native speaker in the market reviews it, and it ships. It has worked for the help centre, the transactional emails and the checkout for years, and it has never once broken anything. So when the support agent goes live in Spain, the English prompt goes into the pipeline like any other string file, and what comes back is beautiful: idiomatic, warm, correct, reviewed by somebody who actually answers phones in Madrid. Everybody involved did their job. The file that shipped has no rules in it.

§1The market file

Marisol answers chat for Faro Energy, an electricity retailer selling into Spain and Portugal. The Spanish market file is the English one, translated, with nothing added and nothing dropped.

marisol.es.tg - the localized market file✓ exits 0
# Rol
Eres Marisol, un agente de atencion al cliente de Faro Energy.

# Restricciones
- DEBES pedir un numero de cuenta antes de hablar de una factura.
- NO DEBES prometer un reembolso de mas de 50 euros.
- DEBES limitar cada respuesta a 3 frases como maximo.
- NO DEBES indicar un precio concreto.
- CUANDO un cliente informe de una averia, DEBES escalar la solicitud a un agente humano.
- CUANDO una espera supere los 10 minutos, DEBES ofrecer una llamada de vuelta.
Six rules. An account-number gate, a refund cap, a length bound, a pricing prohibition and two guarded escalations. Every one of them is real policy that somebody argued about in English.
tg check marisol.es.tg - output
$ typeglish check marisol.es.tg
 1 file — 0 error, 0 warning, 0 info
A perfect run. Not one finding, at any severity, in the whole file.

This is the point in a teardown where the paste usually starts producing findings, and this one does not. There is no contradiction, no hedge, no unfilled placeholder, no wall of shouting modals, no unintroduced definite. It is the cleanest file this series has looked at, and it got there by subtraction.

§2The English twin, and which one is cleaner

Here is the file it came from, still in the repo, still the one the Spanish version was generated out of.

marisol.en.tg - the source the pipeline read✓ exits 0
# Role
You are Marisol, a customer support agent for Faro Energy.

# Constraints
- You MUST ask for an account number before you discuss a bill.
- You MUST NOT promise a refund over 50 euros.
- You MUST keep every response to at most 3 sentences.
- You MUST NOT state a specific price.
- WHEN a customer reports an outage THEN you MUST escalate the request to a human agent.
- WHEN a wait is longer than 10 minutes THEN you MUST offer a callback.
Same six rules, same order, same numbers. This one has a finding in it.
tg check, then tg score, both files - output✗ B against C
$ typeglish check marisol.en.tg
marisol.en.tg:9:1  info   prompt/unintroduced-definite  "the request" retrieves something this
  document never introduces - a model must guess which request is meant. Introduce it on
  another line ("You manage a request.") or name it outright.

 1 file — 0 error, 0 warning, 1 info

$ typeglish score marisol.en.tg
marisol.en.tg — B (85/100)  proven errors: none  tiers: base+z3
  planes  runtime 96 (what the model reads) · hygiene 50 (source only)
  facets  enforceability 95 x.21 · hardness 100 x.12 · directness 90 x.08 ·
          consistency 100 x.17 · structure 100 x.12 (hygiene) · annotation 0 x.12 (hygiene) ·
          style 89 x.08 · security 100 x.08

$ typeglish score marisol.es.tg
marisol.es.tg — C (76/100)  proven errors: none  tiers: base+z3
  planes  runtime 85 (what the model reads) · hygiene 50 (source only)
  facets  enforceability 50 x.21 · hardness 100 x.12 · directness 90 x.08 ·
          consistency 100 x.17 · structure 100 x.12 (hygiene) · annotation 0 x.12 (hygiene) ·
          style 100 x.08 · security 100 x.08
The file with a finding scores nine points higher. The file with no findings has style 100, because there is no the request in it to complain about, and enforceability 50, because there is nothing in it at all.

Enforceability is the facet to read here, and it is worth knowing what it measures: the share of candidate rule lines that lower into checkable IR, how many hard rules parse proof-grade, and how many are measurable. On the English file, 95. On its translation, 50. Nothing was softened, nothing was hedged, no number changed. Six rules went in and the facet that counts rules halved.

The test runner states it as a whole number rather than a percentage. Both files get the same single-case suite bolted on, and both pass it.

tg test --dry, English then Spanish - output✗ 1/6 against 0/0
$ typeglish test t.en.tg --dry
 t.en.tg  coverage: 1/6 rules exercised
  · corte — "Mi luz esta cortada desde esta manana." (not run)
       contains "agente humano"
 1 prompt — 0 failed

$ typeglish test t.es.tg --dry
 t.es.tg  coverage: 0/0 rules exercised
  · corte — "Mi luz esta cortada desde esta manana." (not run)
       contains "agente humano"
 1 prompt — 0 failed
0/0. Not zero out of six. There are no rules to be uncovered, so the denominator is gone, and the run still reports 0 failed.
A green check on a translated prompt is not a verdict. It is a report that the analysis had no input.

The mechanism is not subtle once you say it out loud. Every statement type in TypeGlish is recognized by an English keyword: the modals (MUST, NEVER, SHOULD, MAY), the control words (IF, WHEN, UNLESS), the branch words (THEN, OTHERWISE), the copula (IS), the quantifiers, the frequency adverbs. Precedence runs down that list and a line that matches nothing falls through to prose, which is the catch-all. DEBES is not MUST. NUNCA is not NEVER. CUANDO is not WHEN. So six rules translated faithfully become six paragraphs, and paragraphs are exempt from rule analysis by design, because that exemption is what lets a Context block hold free English.

§3One word read, one line missed

Almost nothing survives the translation. One thing does, and it is an accident. Three files, identical except for the single rule in each.

tg score, three phrasings of one Spanish rule - output
$ tail -1 n1.tg
- NUNCA prometas un reembolso de mas de 50 euros.
n1.tg — C (71/100)  proven errors: none  tiers: base+z3
  facets  enforceability 50 x.26 · consistency 100 x.21 · structure 100 x.16 (hygiene) ·
          annotation 0 x.16 (hygiene) · style 100 x.11 · security 100 x.11

$ tail -1 n2.tg
- NO DEBES prometer un reembolso de mas de 50 euros.
n2.tg — C (75/100)  proven errors: none  tiers: base+z3
  facets  enforceability 50 x.23 · hardness 100 x.14 · consistency 100 x.18 ·
          structure 100 x.14 (hygiene) · annotation 0 x.14 (hygiene) · style 100 x.09 · security 100 x.09

$ tail -1 n3.tg
- DEBES prometer un reembolso de mas de 50 euros.
n3.tg — C (71/100)  proven errors: none  tiers: base+z3
  facets  enforceability 50 x.26 · consistency 100 x.21 · structure 100 x.16 (hygiene) ·
          annotation 0 x.16 (hygiene) · style 100 x.11 · security 100 x.11
Two of the three files have no hardness facet at all: with no force word anywhere, there is nothing for it to weigh, and the weights redistribute across the facets that are left. The middle file has hardness 100.

The difference between the second file and the other two is the word NO. Spanish negation collides exactly with the English quantifier NO, which is a real operator sitting in the square of opposition beside all and some. So the compiler reads one token in the entire Spanish prompt, reads it as English, and scores the line as maximally binding on the strength of it. Every NO DEBES rule in the market file is carrying that. It is the closest thing to a false positive in this teardown, and it is worth naming precisely because it flatters the file: the two lines a Spanish speaker would call the hardest prohibitions in the document are the two the compiler agrees are hard, for a reason that has nothing to do with what they say.

Then there is the line nobody thinks to leave alone. Two files, one rule each, differing only in the role line.

d1.tg - Spanish role line✗ 1 info
# Rol
Eres Marisol, un agente de atencion al cliente de Faro Energy.

# Restricciones
- SOLO un agente humano puede aprobar un reembolso.
d2.tg - English role line, same rule✓ 0 findings
# Rol
You are Marisol, a customer support agent for Faro Energy.

# Restricciones
- SOLO un agente humano puede aprobar un reembolso.
tg check d1.tg, then tg check d2.tg - output
$ typeglish check d1.tg
d1.tg:5:1  info   prompt/implied-doer  Nothing in this document says who follows its
  instructions - every imperative implies a doer the model must infer. One declaration
  anchors them all: "You are the dispatcher."

 1 file — 0 error, 0 warning, 1 info

$ typeglish check d2.tg
 1 file — 0 error, 0 warning, 0 info
Line 2 of both files says who the agent is. Only one of them declares it.

You are Marisol, a customer support agent for Faro Energy is a declaration: the copula binds the value and the line renders, so it is simultaneously a fact in the world model and an instruction the model reads. Eres Marisol, un agente de atencion al cliente de Faro Energy is a sentence. It reaches the model and it will work on the model, which is exactly why nobody catches this. What it does not do is register an addressee, so the checker looks at the file and reports, correctly, that nothing in this document says who follows its instructions.

The sigil planes come through untouched, which is the useful half of the finding. Commands and pointers are punctuation rather than vocabulary, so they keep working in any prose language, and a broken one is still a blocking error.

d3.tg - a dangling pointer in a Spanish file✗ 1 error
# Rol
Eres @{agente}, un agente de atencion al cliente de Faro Energy.

# Restricciones
- NO DEBES prometer un reembolso.
structure/undefined-ref: Dangling pointer - @{agente} names nothing. The one language-neutral claim in the file is the one that blocks the build.

§4The edit that arrives in March

None of the above has broken anything yet. The Spanish prompt is a faithful translation of a correct English prompt, so it says the right things and the agent does roughly the right work. A prompt is not a static document, though, and the interesting question about a file with no rule plane is not what it says today. It is what happens the next time somebody edits it.

The Spanish market lead reads a hundred transcripts and concludes the agent is curt. Replies capped at three sentences read as brusque in Spanish, where the courtesy register is longer. So one line gets appended to the market file, in the house style of the lines above it, asking for a minimum of five. The same request lands in the English backlog, and both edits go in.

tg build, the English file after the append - output✗ refused
$ typeglish build edit.en.tg
typeglish build: edit.en.tg refused — nothing written
edit.en.tg:7:1   error  logic/contradiction  Conflicts with line 10. Counted rule — "keep every
  response to at most 3 sentences." vs "keep every response to at least 5 sentences." is
  bound to at most 3 but at least 5 per response. The counts cannot both hold.
edit.en.tg:7:1   error  logic/numeric  Conflicts with line 10. Numeric conflict — "at most 3
  sentences" and "at least 5 sentences" can't both hold.
edit.en.tg:9:1   info   prompt/unintroduced-definite  "the request" retrieves something this
  document never introduces - a model must guess which request is meant.
edit.en.tg:11:1  error  logic/contradiction  Conflicts with line 6. Counted rule — "keep every
  response to at most 3 sentences." vs "keep every response to at least 5 sentences." is
  bound to at most 3 but at least 5 per response. The counts cannot both hold.
edit.en.tg:11:1  error  logic/numeric  Conflicts with line 6. Numeric conflict — "at most 3
  sentences" and "at least 5 sentences" can't both hold.

 1 file — 4 error, 0 warning, 1 info
Four blocking errors on one appended line, from two different layers, and nothing is written. The English pull request cannot merge.
edit.es.tg - the identical edit, in Spanish✓ exits 0
# Rol
Eres Marisol, un agente de atencion al cliente de Faro Energy.

# Restricciones
- DEBES pedir un numero de cuenta antes de hablar de una factura.
- NO DEBES prometer un reembolso de mas de 50 euros.
- DEBES limitar cada respuesta a 3 frases como maximo.
- NO DEBES indicar un precio concreto.
- CUANDO un cliente informe de una averia, DEBES escalar la solicitud a un agente humano.
- CUANDO una espera supere los 10 minutos, DEBES ofrecer una llamada de vuelta.
- DEBES limitar cada respuesta a 5 frases como minimo.
Three sentences maximum on line 7 and five sentences minimum on line 11. 0 error, 0 warning, 0 info, and it builds to 84328e5681b7.

The score does not move either: C (76/100) before the append and C (76/100) after, because the grade had nothing to grade in the first place. So the market file ships a prompt containing two mutually exclusive length rules, the model resolves the conflict however it resolves it, and the only signal anybody gets is a Spanish CSAT number drifting for a reason nobody can name. Meanwhile the English pull request for the same policy change is red, with a message naming both lines and both numbers, which is the version of that conversation you want to be having.

That asymmetry is the real cost, and it is not about today's file. It is about every edit for the next two years. The English prompt has a compiler standing behind it and the market files do not, and the market files are exactly the ones edited by people furthest from the repo. Softening a rule quietly removes it from the grade; translating one removes the whole file from the argument.

§5The fix: rules in English, copy in a literal zone

The move is to stop treating the prompt as a string file. A .tg file is source, the thing the model reads is an artifact, and the market difference belongs in the artifact. That splits the localized file into two kinds of text that were previously one kind: the rules, which are for the compiler and the next engineer, and the fixed customer-facing copy, which is for the customer and has to be exactly right in-market. Only the second kind gets translated.

marisol.tg - one file, one market✓ A (99/100)
<$CONFIG>
  $IMPORT route human_agent
</$CONFIG>

<role>
  @@ the role line registers the doer, so it stays in English in every market
  You are Marisol, a customer support agent for Faro Energy.
</role>

<constraints>
  @@ market ES: the reply language is a rule, not a property of the source file
  - You MUST write every reply in Spanish.
  @@ identity before account data
  - You MUST ask for an account number before you discuss a bill.
  @@ finance sets the cap; above it a human decides
  - You MUST NOT promise a refund over 50 euros.
  @@ CX-311: 3 sentences is what the chat widget shows without a scroll
  - You MUST keep every reply to at most 3 sentences.
  @@ quoted prices go stale and bind the company
  - You MUST NOT state a specific price.
  @@ an outage is a network matter, never ours to answer
  - WHEN a customer reports an outage THEN you MUST escalate to human_agent.
</constraints>

<"frases_fijas">
  Saludo: Hola, soy Marisol de Faro Energy. ¿Cómo puedo ayudarte?
  Cierre: Gracias por tu paciencia. Que tengas un buen día.
  Espera: Dame un momento, por favor, mientras lo compruebo.
</"frases_fijas">
0 error, 0 warning, 0 info at A (99/100), enforceability 95, annotation 100. Builds to f615fadf1745.

Three decisions are worth pulling out, because each one was previously made by the translation pipeline rather than by a person.

  • The reply language became a rule. You MUST write every reply in Spanish is one English line, it lowers into the rule plane like any other, and it puts the decision where a reviewer and a compiler can both see it. Nothing about a source file's language obliges the output to match, and the moment you write it down you can also branch it: for one prompt serving several markets, that line is a typed input and a switch instead.
  • The sections became tags. That is forced rather than chosen. A literal zone is an XML section, and one XML section anywhere makes XML the file's structure model, so the surviving # headings turn into structure/heading-outside-section warnings and take structure from 100 to 40. Convert the whole file or convert none of it.
  • The canned phrases went inside quotes. <"frases_fijas"> rather than <frases_fijas>, and that pair of quote marks is the entire difference between shipping the copy and shipping a paragraph of it.
tg build, plain tag against quoted tag - the artifacts✗ same source, two outputs
$ typeglish check plain.tg          # the canned phrases in <frases_fijas>
 1 file — 0 error, 0 warning, 0 info
$ typeglish build plain.tg
 built .typeglish/dist/plain.txt ← plain.tg (98da135b1d79, full)
$ tail -3 .typeglish/dist/plain.txt
<frases_fijas>
Saludo: Hola, soy Marisol de Faro Energy. ¿Cómo puedo ayudarte? Cierre: Gracias por tu paciencia. Que tengas un buen día. Espera: Dame un momento, por favor, mientras lo compruebo.
</frases_fijas>

$ typeglish build marisol.tg        # the canned phrases in <"frases_fijas">
 built .typeglish/dist/marisol.txt ← marisol.tg (f615fadf1745, full)
$ tail -5 .typeglish/dist/marisol.txt
<frases_fijas>
  Saludo: Hola, soy Marisol de Faro Energy. ¿Cómo puedo ayudarte?
  Cierre: Gracias por tu paciencia. Que tengas un buen día.
  Espera: Dame un momento, por favor, mientras lo compruebo.
</frases_fijas>
Both files check at 0 error, 0 warning, 0 info. One artifact has three canned phrases and one has a paragraph containing three canned phrases, and the tag emits bare either way. The accented characters survive both builds byte for byte.

The plain tag is a prose body, and a prose body reflows: newlines are not preserved, so Saludo, Cierre and Espera arrive at the model as one run of text with the labels buried in it. Nothing warns you, because nothing is wrong. The quoted form is the escape hatch at section scale: the body stays verbatim, the interior is exempt from analysis, and the tag emits without its quotes. For localized copy that a legal or brand reviewer signed off on, verbatim is the only acceptable contract.

§6Common questions

Can I translate my agent's system prompt into another language?
You can translate the copy the customer reads. You cannot translate the rules, because the rules are made of English operator words. A six-rule Spanish support prompt checks at 0 error, 0 warning, 0 info and reports coverage: 0/0 rules exercised, while the English original it was translated from is 0 error, 0 warning, 1 info at coverage: 1/6. DEBES is not MUST, NUNCA is not NEVER, and CUANDO is not WHEN, so every rule in the Spanish file classifies as prose: it still reaches the model, and nothing about it is checked, counted or proved. Keep the rules in English, make the reply language a rule of its own, and put the localized customer-facing strings in a quoted literal zone.
Why does typeglish check find nothing in my non-English prompt?
Because there is nothing in the rule plane to find. Every statement type in TypeGlish is recognized by an English keyword, so a translated line falls through to prose, which is the catch-all and is exempt from rule analysis. A clean run on a translated file is not a verdict on the file; it is a report that the analysis had no input. The score says so where the check does not: the Spanish file is C (76/100) with enforceability 50 against B (85/100) with enforceability 95 for the English original, and check --strict changes neither, because strict escalates findings and there are none.
Should the system prompt be in the same language as the reply?
No. Treat the reply language as a rule rather than a property of the source file: You MUST write every reply in Spanish is one English line that survives every check, and it puts the decision somewhere a reviewer and a compiler can both see it. The source file is code, the reply is output, and they do not have to match. The one place localized text genuinely belongs in the file is the fixed customer-facing copy, and that goes in a literal zone.
Where do localized canned phrases go in a .tg file?
In a quoted literal zone, which keeps the body verbatim and emits the tag bare. Three Spanish canned phrases inside a plain tag check at 0 error, 0 warning, 0 info and still build to an artifact that joins all three into one line, because a prose body reflows. The identical content inside a quoted tag builds to a different artifact that keeps three lines and their indentation, accented characters included. The check is silent either way, so the difference only shows up in the artifact you deploy.
Does the role line have to stay in English?
Yes, if you want the prompt to have a registered doer. You are Marisol, a customer support agent for Faro Energy is a declaration that binds the addressee. Eres Marisol, un agente de atencion al cliente de Faro Energy is a sentence. Two files identical except for that one line differ by exactly one finding: the Spanish role line leaves a prompt/implied-doer info reading Nothing in this document says who follows its instructions, and the English one is 0 error, 0 warning, 0 info. The role line is the last line anybody thinks to leave alone and the first one that matters.
Field note

Every other paste in this series arrives with a symptom. A pasted policy doc brings a world it never declares, a handbook brings a building, a QA rubric brings the wrong grammar, and in each case the checker has something to say the moment you run it. A translated prompt is the only paste we have looked at that gets quieter as it gets worse, and that inverts the habit the tool trains in you. The useful reflex on a market file is not to read the findings, it is to read the denominator: coverage: 0/0 rules exercised is a louder statement about a support prompt than any error we could have printed, and it took a command nobody runs on a file nobody edits to surface it. If you own a prompt in more than one language, the cheapest possible CI gate is a floor on the count, not on the grade. A file whose rule count is zero should never be able to deploy, whatever colour the check came back.

∿ washed up Aug 25, 2026 ∿