Bake-off: write the rule vs. show the example
Every prompt review turns into this argument eventually. One policy, three files, and a checker that reads one of the two planes and copies the other one straight through.
TL;DR A $EXAMPLE block reaches the model and is invisible to every check in the toolchain: the same pricing conflict is 2 blocking logic/contradiction errors written as two rules, and 0 error, 0 warning, 0 info at consistency 100 written as a rule plus a - good:: that breaks it. Put the policy in rules, where the compiler can defend it, and keep examples for the one thing a rule cannot carry, which is the shape of a good answer.
The argument is usually about tokens or about which one the model "listens to" more, and neither side ever produces evidence. There is a third question nobody asks, and it is the only one with a hard answer: which of the two can you check? Three files with the same four policies, one written as rules, one as examples, one as both.
§1One policy, three files
A chat desk at a broadband provider. Four things have to be true of every reply: no monthly price, pricing goes to sales, at most three sentences, and a case gets opened before anybody promises a callback. Route A writes all four as rules.
<$CONFIG> $IMPORT tool open_case </$CONFIG> # Role @@ role: chat desk for a consumer broadband ISP, pricing and callbacks rail-guarded You are a chat support agent for Harbourline, a broadband provider. # Constraints @@ no_price: published rates change every quarter and a quoted rate binds us - You MUST NOT state a monthly price. @@ sales_route: pricing intent belongs to the sales desk - You MUST direct every pricing question to sales. @@ brevity: a chat reply is read on a phone between other tasks - You MUST keep every reply to at most 3 sentences. @@ case_first: a promised callback that is not in the queue is a callback nobody makes - You MUST call @[open_case] before you promise a callback.
Route B says the same four things by demonstrating them. No rules at all, three $EXAMPLE blocks, each carrying the ideal answer and the answer to avoid.
# Role @@ role: chat desk for a consumer broadband ISP, pricing and callbacks rail-guarded You are a chat support agent for Harbourline, a broadband provider. $EXAMPLE pricing - input:: How much is Fibre 500 a month? - good:: Sales holds the current rates and can send them over today. Shall I pass your details across? - bad:: Fibre 500 is 42 pounds a month on a 24-month contract. $EXAMPLE brevity - input:: My connection drops every evening around eight. - good:: That pattern usually points at congestion on your line. I can book an engineer or run a line test now. Which would you prefer? - bad:: Thank you so much for reaching out to Harbourline today, and I am very sorry to hear that your connection has been dropping in the evenings, which must be extremely frustrating for you. Let me walk you through the possible causes one at a time. $EXAMPLE callback - input:: Can someone ring me back tomorrow morning? - good:: I have opened a case and put you down for a morning callback. You will get a text with the case number. - bad:: Of course, someone will ring you tomorrow morning.
Route C is both: the four rules from route A, then the three examples from route B, in one file. Every version checks.
$ npx typeglish check rules.tg shots.tg both.tg
✓ 3 files — 0 error, 0 warning, 0 info
$ npx typeglish score rules.tg
rules.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 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
$ npx typeglish score shots.tg
shots.tg — B (84/100) proven errors: none tiers: base+z3
planes runtime 100 (what the model reads) · hygiene 63 (source only)
facets consistency 100 x.29 · structure 100 x.21 (hygiene) · annotation 25 x.21 (hygiene) · style 100 x.14 · security 100 x.14
$ npx typeglish score both.tg
both.tg — A (92/100) proven errors: none tiers: base+z3
planes runtime 96 (what the model reads) · hygiene 82 (source only)
facets enforceability 85 x.21 · hardness 100 x.12 · directness 100 x.08 · consistency 100 x.17 · structure 100 x.12 (hygiene) · annotation 63 x.12 (hygiene) · style 100 x.08 · security 100 x.08
§2Three facets that never show up
enforceability, hardness and directness are not scored badly in route B. They are absent. The weights of the remaining five inflate to cover the gap, which is why consistency reads x.29 there and x.17 everywhere else. Those three facets measure rules, and the file has no rules, so there is nothing to measure and the scorer says so by omission rather than by penalty.
Which produces the number worth staring at: runtime 100 (what the model reads). On the plane that describes the document going to the model, the examples-only prompt is perfect. It is perfect the way an empty test suite is green. Route A, with four real obligations in it, scores runtime 96, because it has content that can be assessed and some of it is imperfect.
A prompt made of examples does not score well. It scores absent.
The annotation gap has a harder edge to it. Route A reads annotation 100: five eligible statements, five @@ notes. Route C reads 63, which is five out of eight, and the three unannotated statements are the three $EXAMPLE blocks. So put a note above each one.
$ npx typeglish check noted.tg noted.tg:19:1 error structure/unattached-annotation A `@@` annotation documents the statement DIRECTLY below it — here the next line is a compiler command. Move the note to the line immediately above its statement. noted.tg:25:1 error structure/unattached-annotation A `@@` annotation documents the statement DIRECTLY below it — here the next line is a compiler command. Move the note to the line immediately above its statement. noted.tg:31:1 error structure/unattached-annotation A `@@` annotation documents the statement DIRECTLY below it — here the next line is a compiler command. Move the note to the line immediately above its statement. ✗ 1 file — 3 error, 0 warning, 0 info
annotation facet counts an $EXAMPLE as an eligible statement, and the parser refuses to attach a note to one, because the next line is a compiler command rather than a statement. Route C's 63 is not laziness. It is a ceiling. A $SWITCH block, by contrast, takes a note happily, which is worth knowing before you spend an afternoon on it.§3The example that breaks the rule
All of the above is bookkeeping. This is the part that decides the bake-off. Two files, the same conflict, written two ways. The first is a prohibition and a demonstration of breaking it; the second is the same two claims as two rules.
# Role You are a chat support agent for Harbourline, a broadband provider. # Constraints - You MUST NOT state a monthly price. $EXAMPLE pricing - input:: How much is Fibre 500 a month? - good:: Fibre 500 is 42 pounds a month on a 24-month contract.
$ npx typeglish check drift.tg drift-rules.tg drift-rules.tg:5:1 error logic/contradiction Conflicts with line 5. Logical conflict — "state a monthly price" is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...). drift-rules.tg:6:1 error logic/contradiction Conflicts with line 4. Logical conflict — "state a monthly price" is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...). ✗ 2 files — 2 error, 0 warning, 0 info $ npx typeglish score drift.tg drift.tg — B (87/100) proven errors: none tiers: base+z3 planes runtime 100 (what the model reads) · hygiene 50 (source only) facets enforceability 100 x.21 · hardness 100 x.12 · directness 100 x.08 · consistency 100 x.17 · structure 100 x.12 (hygiene) · annotation 0 x.12 (hygiene) · style 100 x.08 · security 100 x.08
drift-rules.tg holds MUST NOT state a monthly price beside MUST state a monthly price, and the prover refuses to compile it. drift.tg holds the prohibition beside a worked demonstration of a monthly price, and reads consistency 100, enforceability 100, and a clean bill of health.And it ships. The build does not hesitate, and the artifact is a prohibition followed immediately by an illustration of ignoring it.
$ npx typeglish build drift.tg --out-dir dist
✓ built dist/drift.txt ← drift.tg (2dbd9e15320b, full)
$ cat dist/drift.txt
# Role
You are a chat support agent for Harbourline, a broadband provider.
# Constraints
- You MUST NOT state a monthly price.
<example>
User: How much is Fibre 500 a month?
Assistant: Fibre 500 is 42 pounds a month on a 24-month contract.
</example>
This is the same asymmetry that shows up wherever unproved prose sits next to proved rules, and it is worth reading beside the bake-off on where a reason clause goes, where a claim welded onto a rule with because escapes the provers in exactly this way. An example is that failure mode with a bigger surface: a whole sentence of finished, model-facing, brand-approved copy, sitting inside the spec and outside every check.
§4What does get enforced
Not nothing. The block's shape is checked strictly, and the checks are worth knowing because they are the whole list.
$ npx typeglish check shape.tg ptr.tg shape.tg:4:1 error structure/bad-example only "- input::", "- good::", and "- bad::" fields belong in $EXAMPLE pricing — "- response::" is neither. ptr.tg:2:3 warn structure/unused-import Imported tool "open_case" is never used. ✗ 2 files — 1 error, 1 warning, 0 info $ npx typeglish build ptr.tg --out-dir dist ✓ built dist/ptr.txt ← ptr.tg (e20ba3de19b9, full) $ cat dist/ptr.txt # Role You are a chat support agent for Harbourline, a broadband provider. <example> User: Can someone ring me back tomorrow morning? Assistant: I have called @[open_case] and put you down for a morning callback. </example>
ptr.tg imports open_case and writes @[open_case] inside a - good:: body. The pointer is not resolved, so the tool is still never used and the artifact ships the compile-time sigil straight to the model. An example body is literal text, all the way down. If you want a demonstration to reference a tool, name it in words.The last check to fail you is the test harness, and it fails you by being honest about its denominator.
$ npx typeglish test tested.tg --dry ✓ tested.tg coverage: 1/4 rules exercised · price_deflected — "How much is Fibre 500 a month?" (not run) ✓ contains "sales" ✓ at most 3 sentences · callback_opens_case — "Can someone ring me back tomorrow morning?" (not run) ✓ at most 3 sentences ✓ 1 prompt — 0 failed
1/4. The examples are not in the denominator, because coverage measures rules exercised and an example is not a rule. Same story as the score, from the other end of the toolchain.§5The verdict, and the split
Route C wins, but not because more is better. It wins because the two constructs are load-bearing for different things, and the bake-off is really a question about which load each one carries.
- A rule carries the policy. It lowers into logic, it can contradict another rule and be caught, it has a force word the
hardnessfacet can read, it can be pinned by a$TEST, and it appears in the coverage denominator. Everything in the file that somebody could be held to belongs here. - An example carries the shape. Register, length, how much of the diagnosis to give before the question, whether the case number goes in the same sentence. None of that is expressible as a rule anybody would want to read, and all of it is obvious from one good demonstration. That is a real job, and it is the only job.
- A
- bad::field carries the failure mode, and stays home. It is held out of the artifact on purpose, so it costs nothing to be specific in it.
Which leaves one review habit worth adopting, since no command will do it for you: every - good:: response in the file has to read as a compliant answer to every rule in the file. That is a two-minute reading, it catches the drift in §3 before it ships, and it is the only gate that exists. Examples are the part of your prompt where a good example quietly becomes the bad one, and nothing in the toolchain is going to tell you the day it happens.
§6Common questions
- Should I use few-shot examples or instructions in a system prompt?
- Both, carrying different things. Put the policy in rules, because a rule is the only part of the prompt the checker lowers into logic it can prove: four rules and three examples of the same support policy score
A (97/100)andB (84/100)on their own, and the examples-only file is missing theenforceability,hardnessanddirectnessfacets entirely, because it contains nothing those facets can measure. Then keep examples for what a rule cannot carry, which is the shape and the register of a good answer. The combined file isA (92/100)and is the one to ship. - Does TypeGlish check that my examples follow my rules?
- No, and this is the sharp edge. A file whose only rule is You MUST NOT state a monthly price, with an
$EXAMPLEwhose- good::response is Fibre 500 is 42 pounds a month on a 24-month contract, is0 error, 0 warning, 0 infoatB (87/100)withconsistency 100, and it builds. Write the same conflict as two rules and it is 2 blockinglogic/contradictionerrors and the build refuses. The example plane is copied to the model, never proved, so a demonstration that contradicts a rule is a defect only a human review will catch. - What does the checker enforce on an $EXAMPLE block?
- Its shape, not its content. Only
- input::,- good::and- bad::are legal fields, and anything else is a blockingstructure/bad-exampleerror naming the offending key. The content is treated as literal text: a@[lookup]tool pointer written inside a- good::body is not resolved, so the tool still reportsstructure/unused-importand the artifact ships the line to the model with the@[ ]sigil still attached. - Does a
- bad::example get sent to the model? - Never. The
- good::response is emitted as a User / Assistant pair inside an<example>wrapper, and the- bad::response is held out of the artifact entirely, on the grounds that a demonstrated bad answer invites imitation. Three examples with both fields build to 637 bytes containing only the three good responses. The bad ones stay in the source, where they document the failure mode and feed evals.
The reason this asymmetry is uncomfortable rather than merely interesting is that examples are the part of a contact-centre prompt with the best provenance. The rules were written by whoever was on the project; the examples were lifted out of a macro library that legal signed off on, or out of a transcript from the agent everybody agrees is the best on the floor. They feel like the trustworthy half. They are also the half where a price, a timeframe, or a policy from two quarters ago can sit in finished prose for a year, ship to the model in every single conversation, and never once appear in a diagnostic. Provenance is not verification, and on this plane there is no verification at all: only somebody reading it. Few-shot examples are a type system you have not written down, and this is the part where nobody type-checks it.