The tone is casual. Your tone is formal. Both ship.
Two sentences in one file, exact opposites, and the whole toolchain has nothing to say. Not because the checker missed it, but because the two sentences are about two different objects, and one of them is not your agent.
TL;DR An attribute claim is stored against its owner, so Our tone is casual lands on we.tone and Your tone is formal lands on you.tone, and a prompt holding both is 0 error, 0 warning, 0 info at B (84/100) with consistency 100; put both on one owner and the identical policy is 2 blocking logic/contradiction errors at F (67/100). The one spelling that warns you is the ownerless The tone is casual, which prints prompt/unowned-attribute, and taking that finding's second suggested repair makes the file score higher and go silent while the contradiction is still in it.
Your prompt has a tone section. Somebody in brand wrote it, or it was pasted out of a tone-of-voice deck, and it is the one part of the file nobody reviews in a pull request because it does not look like logic. It is logic. Every line in it assigns a value to a slot, the same way at most 3 sentences does, and the compiler will prove two of those lines cannot both hold. It will just never do it across the boundary you actually have.
§1A file that contradicts itself in silence
Cobble Lane sells homeware online. Its chat support prompt is eleven lines. The Role block was written by the prompt engineer; the Voice block was pasted in from the brand guide six weeks later, by somebody else, in the brand guide's own voice.
# Role You are a chat support agent for Cobble Lane, an online homeware retailer. Your tone is formal. # Voice Our tone is casual. The response's length is brief. # Constraints - MUST keep every response to at most 3 sentences. - ALWAYS ask for an order number. - IF a customer is angry THEN escalate to a team leader.
Formal and casual are the two poles of one axis. The compiler knows that: it has a formality axis, and it will refuse a file that puts both values in one slot. Run it.
$ typeglish check voice.tg ✓ 1 file - 0 error, 0 warning, 0 info $ typeglish check voice.tg --strict ✓ 1 file - 0 error, 0 warning, 0 info $ typeglish score voice.tg voice.tg - B (84/100) proven errors: none tiers: base+z3 planes runtime 95 (what the model reads) · hygiene 50 (source only) facets enforceability 83 x.21 · hardness 100 x.12 · directness 100 x.08 consistency 100 x.17 · structure 100 x.12 · annotation 0 x.12 style 100 x.08 · security 100 x.08 lever annotation 0/100 (up to +12 overall)
--strict escalates nothing, because there is nothing to escalate. And consistency 100, which is the facet whose entire job is measuring the rules against each other, on a file whose second sentence and fifth sentence are opposites.The artifact ships both, one after the other, in the order they were written.
$ typeglish build voice.tg ✓ built .typeglish/dist/voice.txt ← voice.tg (c302f88c4fc4, full) # Role You are a chat support agent for Cobble Lane, an online homeware retailer. Your tone is formal. # Voice Our tone is casual. The response's length is brief. # Constraints - MUST keep every response to at most 3 sentences. - ALWAYS ask for an order number. - IF a customer is angry THEN escalate to a team leader.
§2The owner is part of the address
The reason is one line of diagnostic text you only see when the file does break. Write both claims about the same owner and the checker names the slot outright.
$ typeglish check voice-you.tg # "Our tone is casual." -> "Your tone is casual." voice-you.tg:3:1 error logic/contradiction Conflicts with line 5. Contradiction - "you.tone" is assigned "formal" and "casual", opposite sides of formality (one truth per dimension). voice-you.tg:6:1 error logic/contradiction Conflicts with line 3. Contradiction - "you.tone" is assigned "formal" and "casual", opposite sides of formality (one truth per dimension). ✗ 1 file - 2 error, 0 warning, 0 info # exit 1, build refused $ typeglish score voice-you.tg voice-you.tg - F (67/100) proven errors - grade capped at F tiers: base+z3 planes runtime 73 (what the model reads) · hygiene 50 (source only) facets enforceability 83 x.21 · hardness 100 x.12 · directness 100 x.08 consistency 0 x.17 · structure 100 x.12 · annotation 0 x.12
you.tone. That is the slot, and the dot is doing all the work: the owner is not context for the claim, it is half the key the claim is filed under. consistency goes 100 to 0 and the grade is capped at F on a one-word edit that changed no policy whatsoever.So the question is never do these two sentences disagree. It is are these two sentences about the same object, and English is very relaxed about that in exactly the places prompts get written. Here is the whole space: one policy pair, casual against formal, in every spelling a real prompt uses.
the pair slot tg check tg score Your tone is casual. / Your tone is formal. you.tone 2 error F (50/100) The tone is casual. / The tone is formal. the tone 2 error + 2 info F (39/100) Our tone is casual. / Our tone is formal. we.tone 2 error F (50/100) The response's tone .. / The response's tone .. response. 2 error F (54/100) The tone is casual. / Your tone is formal. two slots clean + 1 info C (73/100) Our tone is casual. / The tone is formal. two slots clean + 1 info C (73/100) Our tone is casual. / Your tone is formal. two slots clean C (79/100) The response's tone .. / Your tone is formal. two slots clean C (79/100) $ typeglish check r1.tg r1.tg:2:1 error logic/contradiction Conflicts with line 3. Contradiction - "you.tone" is assigned "casual" and "formal", opposite sides of formality (one truth per dimension). $ typeglish check r3.tg r3.tg:2:1 error logic/contradiction Conflicts with line 3. Contradiction - "we.tone" is assigned "casual" and "formal", opposite sides of formality (one truth per dimension). $ typeglish check r4.tg r4.tg:2:1 error logic/contradiction Conflicts with line 3. Contradiction - "response.tone" is assigned "casual" and "formal", opposite sides of formality (one truth per dimension).
you.tone, we.tone, response.tone, and the unowned the tone. Matched pairs are all blocking and all capped at F. Mixed pairs are all clean, and the two worst rows, the ones with no finding at all, score six points higher than the mixed row that does warn.Read the bottom half again with a prompt review in mind. Our tone is casual beside Your tone is formal is not a contrived pairing. It is the single most common shape in commercial prompt files, because a brand guide is written in the first person plural and a system prompt is written in the second person singular, and the two documents get stapled together by a person who is thinking about the words rather than the referents.
Two sentences only argue if they are about the same thing. Your prompt has three names for your agent and only one of them is you.
§3The finding that fires, and the fix that hides it
One of the eight rows does report something. Write the tone claim with no owner at all and the checker notices the hole.
$ typeglish check voice-bare.tg # "Our tone is casual." -> "The tone is casual." voice-bare.tg:6:1 info prompt/unowned-attribute Unowned attribute - "the tone" names a slot but not its owner, so a model must guess whose tone this is. Own it ("Your tone is ...") or name the owner ("The response's tone is ..."). ✓ 1 file - 0 error, 0 warning, 1 info $ typeglish score voice-bare.tg voice-bare.tg - B (83/100) proven errors: none tiers: base+z3 L6 prompt/unowned-attribute -0.25
Now do the thing the diagnostic tells you to do, and take its second suggestion rather than its first.
before The tone is casual. 0 error, 0 warning, 1 info B (83/100) style 89 after The response's tone is casual. 0 error, 0 warning, 0 info B (84/100) style 100 # and the file still says, four lines up: Your tone is formal.
style from 89 to 100, and the contradiction untouched. The repair was honest advice about a real hole; it just does not know that the owner you name has to be the owner the rest of the file already uses. Naming a different one is a clean way to make the finding disappear without fixing anything.This is the practical lesson and it generalises past tone. When a diagnostic offers you two repairs, one of them is usually the one that makes the file quieter and one is the one that makes the file right, and they are not always the same repair. The score cannot referee that, because a slot with a named owner genuinely is better written than a slot with none. It is better written and still wrong.
§4One slot, one owner, one value
The fix is not clever. Decide who owns each attribute, use that owner everywhere, and delete the duplicates instead of rewording them. For an agent prompt the owner is you, because that is the object every rule in the file is already addressed to, and because the Role declaration introduces it on the line above.
# Role @@ role: the owner every attribute below attaches to You are a chat support agent for Cobble Lane, an online homeware retailer. @@ tone: one slot, one owner, one value - the brand guide won, the legacy formal went Your tone is casual. # Constraints @@ brevity: the measurable version of "keep it brief", so a $TEST can assert it - MUST keep every response to at most 3 sentences. @@ order_number: the order number is what unlocks the account context - ALWAYS ask for an order number. @@ anger_escalation: a heated customer gets a human - IF a customer is angry THEN escalate to a team leader.
$ typeglish score voice-shipped.tg voice-shipped.tg - A (96/100) proven errors: none tiers: base+z3 planes runtime 95 (what the model reads) · hygiene 100 (source only) facets enforceability 83 x.21 · hardness 100 x.12 · directness 100 x.08 consistency 100 x.17 · structure 100 x.12 · annotation 100 x.12 style 100 x.08 · security 100 x.08 $ typeglish build voice-shipped.tg ✓ built .typeglish/dist/voice-shipped.txt ← voice-shipped.tg (e08734e99a96, full) # Role You are a chat support agent for Cobble Lane, an online homeware retailer. Your tone is casual. # Constraints - MUST keep every response to at most 3 sentences. - ALWAYS ask for an order number. - IF a customer is angry THEN escalate to a team leader.
B (84/100) to A (96/100), and the whole # Voice section is gone. The response's length is brief did not need a better owner, it needed deleting: at most 3 sentences two lines down is the same claim with a number on it, and a soft duplicate of a measurable rule is dead weight in front of the model.Note what the grade is actually rewarding. consistency was 100 before and 100 after, because nothing was ever proven either way; the twelve points came from annotation and from removing a line the model did not need. That is the honest reading of this defect: the score cannot see it, before or after, and the reason to fix it is that your agent's replies stop wandering, not that a number moves.
§5The audit, in one pass
This takes about ten minutes on a real file and it is worth doing before your next tone pass, not after.
line the claim owner slot 3 Your tone is formal. you you.tone <- conflict 6 Our tone is casual. we we.tone <- conflict 7 The response's length is brief. the response response.length <- soft dup 10 MUST ... at most 3 sentences. (a rule) - the words worth grepping for: tone voice register style length manner approach personality the owners worth grepping for: your our the its the response's the agent's the assistant's the reply's
Two adjacent habits make it stick. Put every attribute claim directly under the Role declaration that introduces its owner, so a second author has to walk past the existing tone line to add another one. And prefer a measurable rule to an attribute wherever one exists: at most 3 sentences cannot be duplicated by a differently-owned adjective, because a bound lives in the numeric layer where the prover reaches it regardless of who is speaking. Which adjectives sit on which axis, and what to do with one the compiler has never heard of, is the subject of a brand voice that cancels itself out; this post is the layer underneath it, where the axis is fine and the owner is not.
The general shape is worth keeping past tone. Every proof in this compiler is a comparison between two claims in one slot, and a slot is an address with several parts: the owner, the attribute, sometimes the scope. Change any part and the two claims stop meeting. That is the same mechanism by which a qualifier hides a contradiction, which you did not narrow that rule, you moved it takes apart from the other end, and it is why a clean check is a statement about what was compared rather than about what is true.
§6Common questions
- Why does my agent's tone change between replies?
- Because two lines of your prompt are telling it two different things and nothing has ever compared them. A tone claim is stored against an owner, so
Our tone is casuallands onwe.toneandYour tone is formallands onyou.tone, and two values in two different slots are not a conflict at all: that file is0 error, 0 warning, 0 info, identical under--strict, and scoresB (84/100)withconsistency 100. Grep your prompt for tone, voice, register, length and style, list the owner of each claim, and if you find more than one owner for a slot you have found the reason the replies wander. - What does prompt/unowned-attribute mean?
- It means you wrote
The tone is casualand never said whose tone. The message reads the tone names a slot but not its owner, so a model must guess whose tone this is, and it offers two repairs: own it (Your tone is ...) or name the owner (The response's tone is ...). It is an info, worth-0.25on the score ledger, and it is the only spelling of an ownerless attribute that says anything at all.Our tone is casualhas an owner,we, so the finding does not fire, and that file is completely silent while carrying exactly the same defect. - Does TypeGlish catch a contradiction between my Role section and my tone section?
- Only when both claims land on the same slot.
Your tone is formalagainstYour tone is casualis 2 blockinglogic/contradictionerrors namingyou.toneassigned formal and casual, opposite sides of formality, atF (67/100)withconsistency 0and the build refused. The identical policy written asOur tone is casualagainstYour tone is formalis0 error, 0 warning, 0 infoatB (84/100). Same two words, same two lines, and the only difference is whether the two sentences are about the same object. The prover is not being lenient, it is being asked about two different things. - How do I write a tone section an agent will actually follow?
- One slot, one owner, one value, and then measurable rules for everything else. Pick the owner the rest of the file already uses, which for an agent prompt is
you, put the tone claim on the line under the Role declaration so the owner is introduced before it is used, and delete every other copy rather than rewording it. On the prompt in this post, collapsing a Role line and a Voice section into a singleYour tone is casualand turning the vague length claim into an existingat most 3 sentencesrule tookB (84/100)toA (96/100), with the artifact 61 bytes shorter and containing exactly one sentence about tone.
The tell that you have this defect is a team reaching for the inference settings. Wandering voice is a symptom people attribute to temperature, because that is the dial with the word randomness next to it, and turning it down does make the replies more similar to each other without making them more like the voice you asked for. Before you touch a sampling parameter, count the sentences in your prompt that assign a personality to something, then count how many distinct things they assign it to. A Role line, a pasted brand block, a QA rubric and a channel override is four owners for one slot and something like a hundred tokens of tone instruction on every turn, most of it arguing. If that second count is not one, the fix is in the file and it is free.