← Tidelines/Teardowns

Teardown: the policy doc somebody pasted into your agent

Ops sends over the returns policy and asks for it to be “in the bot”. You paste it in, the checker says zero errors, and three weeks later the agent is quoting a return window nobody at the company has ever offered.

by TypeGlish team7 min read#teardowns
Which window?

TL;DR A policy document pasted into an agent prompt compiles clean, because a policy is written about a process and a prompt is written to an agent: the checker returns 0 errors and 7 info findings, and those findings (prompt/implied-doer, prompt/unintroduced-definite) are an exact list of the nouns the model has to guess. Introduce each one and the same file goes C (71/100) to A (95/100), with its numbers turned into slots the compiler can prove conflicts on.

The pasted policy is the most common way a real rule enters an agent prompt. Somebody in operations owns the returns policy, that policy lives in a doc, and when the bot gets it wrong the fastest fix in the world is to copy the relevant paragraph into the system prompt. It is not lazy. The document is the source of truth, and the person pasting it is doing the right thing with the artifact they were handed. The problem is that the document was written for a reader who already works at the company, and the agent is the only reader who does not.

We are going to tear one down. To keep the interesting part visible, this file has already had its typography swept: no em-dashes, no curly quotes, no decorative bullets. That layer is loud and mechanical, and it is the subject of teardown: the system prompt an AI wrote for you. What survives the character sweep is the harder problem.

§1The paste, and the green check

Five rules, lifted from the returns handbook, dropped into the prompt under their own heading. Read it as an operations person would: it is correct, it is complete, and every line is something the agent genuinely must do.

returns.tg✓ compiles · C (71/100)
# Returns and refunds
- ALWAYS check the returns window before offering a refund.
- MUST send the case to the escalation queue when the customer is a reseller.
- NEVER confirm a replacement before the warehouse checks stock.
- ALWAYS log the reason code on the ticket.
- MUST offer store credit when the customer has no receipt.
Nothing here is wrong. That is the whole difficulty: every review this file gets from a human will pass it, because every human reviewing it knows what the returns window is.
tg check - output
returns.tg:2: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."
returns.tg:2:1  info   prompt/unintroduced-definite  "the returns window" retrieves something
  this document never introduces - a model must guess which window is meant.
returns.tg:3:1  info   prompt/unintroduced-definite  "the case" ...
returns.tg:3:1  info   prompt/unintroduced-definite  "the escalation queue" ...
returns.tg:4:1  info   prompt/unintroduced-definite  "the warehouse" ...
returns.tg:5:1  info   prompt/unintroduced-definite  "the reason code" ...
returns.tg:5:1  info   prompt/unintroduced-definite  "the ticket" ...

 1 file — 0 error, 0 warning, 7 info
Zero errors. Zero warnings. A build gate that only watches the exit code lets this through, and should: nothing in the file is provably false. The findings are all in the tier below, and the repeated message bodies are trimmed here for width. Seven of them, on five lines.

§2Seven nouns the model has to guess

The definite article is not decoration. In English, the is a lookup instruction: it tells the reader to retrieve a specific thing that the conversation has already established. When a prompt says the returns window, it is not describing a window, it is pointing at one, and the model dutifully goes looking. If the document never put a window there, the model resolves the pointer from the only other place it can: everything it has ever read.

Go line by line and ask what the retrieval actually returns.

  • the returns window - the single most expensive one. There is no number anywhere in the file, so the model supplies the modal answer from its training data, and that answer is usually 30 days. If yours is 14, the agent follows your rule perfectly and quotes a policy you do not have.
  • the escalation queue - resolves to whatever the model thinks an escalation queue is, which is a concept rather than a destination. In practice the agent says it has escalated and nothing arrives anywhere.
  • the warehouse - fine if you have one. If you have three, the rule is silently about none of them.
  • the reason code - the model will invent a taxonomy. It will be a reasonable taxonomy, and it will not be yours, and your weekly report is built on the codes.
  • the ticket and the case - two names for the same record, on adjacent lines, which is how the source document referred to it. The checker cannot know they are one thing, and neither can the model.

That last pair is the tell that this text came from somewhere else. A document written for humans is allowed to vary its nouns for readability. A specification is not.

The seventh finding is different in kind. prompt/implied-doer fires once per document, and it says nobody has been told who is being instructed. A policy doc never needs an addressee, because the reader is holding it and knows they are the reader. A prompt with five imperatives and no You are line is asking the model to infer the actor before it can apply a single rule, and the inferred actor is whatever the rules make it sound like. This is a close cousin of the subject drift picked apart in half your rules are about somebody else: there, the rules had a subject and it was the wrong one; here, they have none at all.

§3A prose block does not hide it, and neither does strict

The reflex, once a wall of findings appears, is to move the pasted text somewhere the checker is not looking. TypeGlish has such places: # Context, # Background, # Notes and their siblings are prose blocks, exempt from rule analysis, exactly so that genuine background prose does not get parsed as policy. It is a reasonable guess that dropping the paste in there will quiet things down.

tg check - the same five lines, moved into # Context
returns.tg:2:1  info   prompt/implied-doer       ...
returns.tg:2:1  info   prompt/unintroduced-definite  "the returns window" ...
returns.tg:3:1  info   prompt/unintroduced-definite  "the case" ...
returns.tg:3:1  info   prompt/unintroduced-definite  "the escalation queue" ...
returns.tg:4:1  info   prompt/unintroduced-definite  "the warehouse" ...
returns.tg:5:1  info   prompt/unintroduced-definite  "the reason code" ...
returns.tg:5:1  info   prompt/unintroduced-definite  "the ticket" ...

 1 file — 0 error, 0 warning, 7 info
Identical. Seven findings, same lines, same codes. The prose-block exemption covers rule analysis, and this is not rule analysis: it is discourse. Whether a noun has a referent does not depend on which section it sits in, because the model reads the whole file either way.

The other reflex is check --strict, which escalates every IMPORTANT finding to a blocking error and is the right answer surprisingly often. Not here. Run it on this file and the summary line is byte-identical to the plain run: 0 error, 0 warning, 7 info. Strict raises correctness defects, and an unintroduced noun is not a defect the compiler can prove, it is a hole the compiler can see. Nobody is going to fail your build over this. That is precisely why it survives to production.

§4Introduce the object, and the numbers become checkable

Here is the part that makes introducing your nouns worth more than tidiness. Take the goodwill number, which in the real handbook appears twice, in two paragraphs, at two amounts, because the damaged-goods section was updated and the no-receipt section was not. Written as ordinary rules, both amounts pass without comment.

two amounts, loose in the prose✓ 0 error, 0 warning, 0 info
# Role
You are a returns agent for Acme, an online retailer.

# Returns and refunds
- MUST offer store credit of up to 25 dollars when the customer has no receipt.
- MUST offer store credit of up to 50 dollars when a delivery arrives damaged.
Two ceilings on one authority, and a perfectly clean run. The checker has no grounds to object: nothing here says these are the same limit. They are two sentences that each mention a number.

Now name the thing. One declaration turns the amount from a number inside a sentence into a value bound to an object, and the second amount stops being a second opinion.

the same two amounts, on a declared object✗ won't build
# Role
You are a returns agent for Acme, an online retailer.

# Context
The goodwill cap is 25 dollars.
The goodwill cap is 50 dollars.

# Returns and refunds
- MUST offer store credit inside the goodwill cap when the customer has no receipt.
tg check - output
returns.tg:5:1  error  logic/measure  Money conflict on goodwill cap — "exactly USD 25" and
  "exactly USD 50" cannot both hold. (with line 5)
returns.tg:6:1  error  logic/measure  Money conflict on goodwill cap — "exactly USD 25" and
  "exactly USD 50" cannot both hold. (with line 4)

 1 file — 2 error, 0 warning, 0 info
Same two numbers, same file, blocking error. The message even names the slot: money conflict on goodwill cap. Declaring an object gives its values somewhere to collide, which is the same machinery that makes a two-amount refund limit provable in why your agent approves refunds it shouldn’t. An undeclared noun is not just unclear to the model. It is invisible to the prover.

§5The rebuild

Nothing below changes a single policy. Every rule from the paste is still there, saying the same thing. What has been added is a doer, a definition for each thing the rules point at, and a @@ note per statement saying why the line exists.

returns.tg (rebuilt)✓ compiles · A (95/100)
# Role
@@ role: the addressee, declared once, so every imperative below has a doer
You are a returns agent for Acme, an online retailer.

# Context
@@ window: the policy number, named here so that no rule has to imply it
The returns window is 30 days from delivery.
@@ queue: names the destination, so "the queue" is never a guess
The escalation queue is Tier 2 Returns.
@@ warehouse: the stock authority this agent defers to
The warehouse is the Acme fulfillment center in Reno.
@@ ticket: the record every logging rule below writes to
The ticket is the record of one customer conversation.
@@ reason_code: the label the weekly returns report is built from
The reason code is the label you put on a closed ticket.
@@ cap: one goodwill number in one place, so a second one is a red build
The goodwill cap is 25 dollars.

# Returns and refunds
@@ window_check: the number is the policy's, and never the model's prior
- ALWAYS check the returns window before offering a refund.
@@ reseller: a reseller return is a contract matter, not a returns matter
- MUST send the ticket to the escalation queue when the customer is a reseller.
@@ stock: a replacement promised before stock is confirmed becomes a second contact
- NEVER confirm a replacement before the warehouse checks stock.
@@ log_reason: every report downstream is built from this label
- ALWAYS log the reason code on the ticket.
@@ no_receipt: store credit inside the declared cap keeps the goodwill inside Acme
- MUST offer store credit inside the goodwill cap when the customer has no receipt.
The two names for one record collapsed into the ticket, which is the edit an ops reviewer would push back on as pedantic and which is the one the model needed most. Note also that the declarations render: a TypeGlish declaration is both a binding and an instruction, so the model reads The returns window is 30 days from delivery as a fact, in those words, in the artifact.
tg check & tg score - after
$ npx typeglish check returns.tg
✓ 1 file — 0 error, 0 warning, 0 info

$ npx typeglish score returns.tg
returns.tg — A (95/100)  proven errors: none  tiers: base+z3
  planes  runtime 93 (what the model reads) · hygiene 100 (source only)
  facets  enforceability 76 x.21 · hardness 100 x.12 · directness 100 x.08 · consistency 100 x.17
          · structure 100 x.12 (hygiene) · annotation 100 x.12 (hygiene) · style 100 x.08 · security 100 x.08
C (71/100) to A (95/100), and seven info findings to zero. The runtime plane, which is the only half the model reads, went 77 to 93 on definitions alone. The rest is the @@ notes, which the model never sees at all.

Ten minutes of work, and none of it was policy work. That is the useful shape of this job: the operations team owns what the rules say, and you own whether the agent can tell what they are about.

Field note

prompt/unintroduced-definite and prompt/implied-doer arrived with the Self-Containedness Law in TypeGlish 0.6.0: paste the prompt you already have, alongside typeglish import, which exists for exactly the situation in this post: it takes the document you already run and hands back a worklist instead of a rejection. Both are built on the same assumption, that the first version of any real prompt is a paste. Every code figure on this page is re-run against the real compiler by CI, so the counts and codes here are what the checker says today, not what it said when this was written.

FAQCommon questions

Can I paste our policy document straight into the system prompt?
You can, and it will compile, which is the trap. A policy document is written about a process for a reader who already works there, so it refers to teams, records and numbers by their in-house names without ever saying what they are. A prompt is written to an agent that has none of that context. Paste the document, then spend ten minutes introducing every noun it assumes: what the returns window is, which queue the escalation goes to, what a reason code is. The paste is the first draft, not the deliverable.
What does prompt/unintroduced-definite mean in TypeGlish?
It fires when a rule says the X and nothing in the file ever says what X is. The definite article is a lookup instruction: the queue tells the model to retrieve a queue it is supposed to already know about. If the document never introduced one, the model retrieves the most plausible queue from its own priors instead, and you never see it happen. The finding is info severity, one per unintroduced noun, and the fix is one line that names the thing.
Why does my agent invent policy details that are not in the prompt?
Usually because the prompt referred to something without defining it, and a plausible completion is cheaper for the model than an admission of ignorance. A rule reading always check the returns window contains no number, so the model supplies one, and 30 days is a very common return window in its training data. If your window is 14 days, the agent will confidently quote the wrong policy while following your rule exactly. Write the number down and the guess has nothing to fill.
Do info-level findings matter if the file compiles?
They matter differently. An error is a defect the compiler can prove; an info finding is a place the compiler is telling you what the model will have to invent. Each one costs a quarter of a point on the TG score, so seven of them barely move the grade, and check --strict does not escalate them either. Read them as a worklist rather than a verdict: they are the shortest list you will ever get of the assumptions your prompt is making on your behalf.
∿ washed up Jul 30, 2026 ∿