Bake-off: the reason in the rule vs. the reason in a note
Everybody writes the why into the rule, because a rule with a reason feels like a rule somebody thought about. Three files with the same three rules, and the checker has an opinion about where the word because should live.
TL;DR A because clause welded to a rule is parsed like part of the rule and proved like nothing: it drags hardness from 100 to 50 when it contains a word like most, drags enforceability from 100 to 70 when it adds a claim with no observable action, and hides a contradiction that the same sentence on its own line reports as 2 blocking errors. Put reasons the model needs in a # Context prose block and reasons the reviewer needs in a @@ note, and the same policy goes from B (81/100) to A (96/100) with an artifact 167 bytes shorter.
This is a small habit with a large blast radius. Nobody debates whether to give a model reasons, and the honest answer is that reasons often help, which is exactly why the question of where the reason goes never gets asked. Three files, one policy, and a checker that treats each placement completely differently.
§1One policy, three files
Three rules from a chat desk at an electricity retailer: a length bound, a pricing rail, and a tool-first rule for callbacks. Every version says the same three things and records the same three reasons. Route A welds each reason to its rule.
<$CONFIG> $IMPORT tool open_case </$CONFIG> # Role You are a chat support agent for Northvale Energy, an electricity retailer. # Constraints - You MUST keep every reply to at most 3 sentences because most customers read on a phone. - You MUST NOT state a tariff price, because published rates change every quarter and a quoted rate binds us. - You MUST call @[open_case] before you promise a callback, so that the callback lands in the queue a human works.
Route B moves each reason to a @@ note, which documents the statement directly below it and is stripped at compile.
<$CONFIG> $IMPORT tool open_case </$CONFIG> # Role You are a chat support agent for Northvale Energy, an electricity retailer. # Constraints @@ brevity: most customers read on a phone - You MUST keep every reply to at most 3 sentences. @@ no_price: published rates change every quarter and a quoted rate binds us - You MUST NOT state a tariff price. @@ callback_case: the callback lands in the queue a human works - You MUST call @[open_case] before you promise a callback.
Route C keeps the notes and also gives the model the background, in a # Context prose block, which is one of the section kinds exempt from rule analysis.
<$CONFIG> $IMPORT tool open_case </$CONFIG> # Role You are a chat support agent for Northvale Energy, an electricity retailer. # Context Most customers reach us from a phone, on a mobile connection, mid-task. Published rates change every quarter, and a rate quoted in a chat binds us to it. A callback that is not in the queue is a callback nobody makes. # Constraints @@ brevity: most customers read on a phone - You MUST keep every reply to at most 3 sentences. @@ no_price: published rates change every quarter and a quoted rate binds us - You MUST NOT state a tariff price. @@ callback_case: the callback lands in the queue a human works - You MUST call @[open_case] before you promise a callback.
§3 gets to.§2The check cannot referee this
$ npx typeglish check rules-a.tg rules-b.tg rules-c.tg
✓ 3 files — 0 error, 0 warning, 0 info
$ npx typeglish score rules-a.tg
rules-a.tg — B (81/100) proven errors: none tiers: base+z3
planes runtime 91 (what the model reads) · hygiene 50 (source only)
facets enforceability 80 x.21 · hardness 83 x.12 · directness 92 x.08 · consistency 100 x.17 · structure 100 x.12 (hygiene) · annotation 0 x.12 (hygiene) · style 100 x.08 · security 100 x.08
$ npx typeglish score rules-b.tg
rules-b.tg — A (95/100) proven errors: none tiers: base+z3
planes runtime 97 (what the model reads) · hygiene 88 (source only)
facets enforceability 90 x.21 · hardness 100 x.12 · directness 100 x.08 · consistency 100 x.17 · structure 100 x.12 (hygiene) · annotation 75 x.12 (hygiene) · style 100 x.08 · security 100 x.08
$ npx typeglish score rules-c.tg
rules-c.tg — A (91/100) proven errors: none tiers: base+z3
planes runtime 97 (what the model reads) · hygiene 72 (source only)
facets enforceability 90 x.21 · hardness 100 x.12 · directness 100 x.08 · consistency 100 x.17 · structure 100 x.12 (hygiene) · annotation 43 x.12 (hygiene) · style 100 x.08 · security 100 x.08
annotation, which obviously moves when you add notes. It is runtime: 91 for route A against 97 for both others. The reason clause is not just untidy bookkeeping, it is measurably changing the document the model reads.Route C sits four points behind route B purely on annotation 43, and that is bookkeeping rather than substance: the three context lines are eligible statements with no notes on them. Put a @@ note above each context line and the same file reads A (96/100) with annotation 86, which is the best score in this bake-off. Nothing about the model-facing text changed.
§3What a because actually costs
Six single-rule files, to attribute the loss. Each pair is the same rule with and without its reason.
$ npx typeglish score bound.tg bound.tg — B (87/100) proven errors: none tiers: base+z3 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 $ npx typeglish score bound-why.tg bound-why.tg — B (81/100) proven errors: none tiers: base+z3 facets enforceability 100 x.21 · hardness 50 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 $ npx typeglish score ban.tg ban.tg — B (87/100) proven errors: none tiers: base+z3 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 $ npx typeglish score ban-why.tg ban-why.tg — B (81/100) proven errors: none tiers: base+z3 facets enforceability 70 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
bound.tg is You MUST keep every reply to at most 3 sentences. and bound-why.tg adds because most customers read on a phone. ban.tg is You MUST NOT state a tariff price. and ban-why.tg adds because published rates change every quarter and a quoted rate binds us. Same six-point drop, two different facets.The hardness half is the more surprising one, and the doctrine explains it exactly.
$ npx typeglish --explain hardness
hardness (score facet — runtime plane, weight 0.15)
THE HARDNESS DOCTRINE (SPEC §15): how BINDING the prompt's language is. Every force word sits on a spectrum (must not ↔ must, never ↔ always, no ↔ all); hardness is its distance from the waver center (THE POLE LAW — both poles bind, the middle wavers), and a statement scores the MIN over its force words (one hedge softens the whole rule). An unhedged command is 1.0; 1.0 renders PURE BOLD in the editor.
raise it: Commit to pole words — MUST / NEVER / ALWAYS / ALL / exact bounds ("at most 3") — and delete the soft middle: should, sometimes, about, try to, as needed each cap their statement below 1.0.
Which predicts the fix, and the prediction holds. Three variants of one rule:
$ npx typeglish score plain-why.tg plain-why.tg — B (87/100) proven errors: none tiers: base+z3 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 $ npx typeglish score most-why.tg most-why.tg — B (81/100) proven errors: none tiers: base+z3 facets enforceability 100 x.21 · hardness 50 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 $ npx typeglish score usually-why.tg usually-why.tg — B (81/100) proven errors: none tiers: base+z3 facets enforceability 100 x.21 · hardness 50 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
most or usually and the obligation above it is worth half as much. That is not a rule you want to be following by accident, and it is not a rule anybody can review for by reading.The clause is not commentary. It is part of the sentence, and the sentence is the rule.
§4The blind spot
If the reason is parsed, the fair expectation is that it is also checked. It is not, and the gap is easy to show with one claim in two positions.
slot.tg # Constraints - You MUST respond within 2 hours. - You respond within 30 minutes. slot-why.tg # Constraints - You MUST respond within 2 hours. - You MUST set an expectation because you respond within 30 minutes.
$ npx typeglish check slot.tg slot-why.tg slot.tg:2:1 error logic/time-strength Conflicts with line 3. One bound per slot — "within 30 minutes" already entails "within 2 hours"; the looser rule on "you · respond" is dead weight. Keep one. slot.tg:3:1 error logic/time-strength Conflicts with line 2. One bound per slot — "within 30 minutes" already entails "within 2 hours"; the looser rule on "you · respond" is dead weight. Keep one. ✗ 2 files — 2 error, 0 warning, 0 info
you · respond, and refused to compile the file. It did not read into the because clause, so the second file is clean. The clause is in the worst position available: shipped to the model, counted against the rule by the score, and out of reach of the provers that would catch it being wrong.That combination is what makes this a placement question rather than a style question. A @@ note is also unproved, but nobody expects a comment to be proved and it costs nothing downstream. A because clause looks like it is inside the spec, is treated as inside the spec by the scorer, and is outside it everywhere it would matter. The same asymmetry shows up wherever unreviewed prose sits next to reviewed rules, which is the argument the Context section rewrite makes about the part of a prompt nobody reads.
§5The verdict, and where each reason goes
$ npx typeglish build rules-a.tg rules-b.tg rules-c.tg --out-dir dist ✓ built dist/rules-a.txt ← rules-a.tg (a12e582f251f, full) ✓ built dist/rules-b.txt ← rules-b.tg (61f33dd55152, full) ✓ built dist/rules-c.txt ← rules-c.tg (b4a40dfc2af4, full) ✓ built 3/3 $ wc -c dist/*.txt 411 dist/rules-a.txt 244 dist/rules-b.txt 473 dist/rules-c.txt $ cat dist/rules-b.txt # Role You are a chat support agent for Northvale Energy, an electricity retailer. # Constraints - You MUST keep every reply to at most 3 sentences. - You MUST NOT state a tariff price. - You MUST call open_case before you promise a callback.
So the verdict is not never explain. It is that a prompt has two audiences with different needs, and one construct cannot serve both:
- The reason the model needs goes in a
# Contextprose block. It reaches the model, it is exempt from rule analysis, and no word in it can weaken an obligation somewhere else in the file. - The reason the reviewer needs goes in a
@@note above its rule. It is stripped at compile, it costs nothing in the artifact, and it is the thing you point at in six months when somebody asks why the bound is three sentences and not five. - The reason welded to the rule is the one to stop writing. It is the only placement that pays for the reason twice, once in tokens and once in strength.
Most reasons turn out to belong in the note. The test is simple and worth applying rule by rule: if the model would behave differently without this sentence, it is context; if only a person would, it is an annotation. Teams tend to discover that four rules in five are the second kind, which is also the finding that makes the annotation facet worth chasing rather than gaming, as the post on letting a coding agent edit your prompt gets into.
§6Common questions
- Should I explain why in a system prompt, or just give the rule?
- Both, in two different places. A reason the model needs in order to apply the rule sensibly belongs in a
# Contextprose block, where it reaches the model and is exempt from rule analysis. A reason only a reviewer needs belongs in a@@note, which is stripped at compile and never costs a token. What does not work is welding the reason onto the rule withbecause: the same three rules scoreB (81/100)with the reasons inline andA (95/100)with the reasons in notes, and the inline artifact is 411 bytes against 244. - Why does adding because to a rule lower the TypeGlish score?
- Because the clause is parsed, not skipped. The
hardnessfacet scores the minimum over a statement's force words, so a quantifier or a frequency word inside the reason becomes the strength of the whole rule: because most customers read on a phone takes hardness from 100 to 50, and because a customer usually reads on a phone does the same, while because customers read on a phone costs nothing. Theenforceabilitydrop has a different cause, that the clause adds rule-shaped text with no observable action in it, which is what takes a prohibition from 100 to 70. - Does TypeGlish check the facts inside a because clause?
- No, and that is the sharp edge. The line You respond within 30 minutes sitting under You MUST respond within 2 hours is 2 blocking
logic/time-strengtherrors. Move the identical claim into a reason clause on the line above and the file is0 error, 0 warning, 0 info. The provers do not read into the clause, but the score facets do, so a reason welded to a rule is in the worst available position: shipped to the model, counted against the rule, and invisible to the checks that would catch it being wrong. - Do
@@notes reach the model? - Never. A
@@note documents the statement directly below it and is stripped at compile, so it costs nothing in the artifact and lives entirely on the hygiene plane, where theannotationfacet scores it. That is what makes it the right home for a rationale a reviewer or an auditor needs: three rules with their reasons in notes build to 244 bytes, the same 244 bytes they would build to with no reasons recorded at all.
There is a version of this that is not about scores at all. Ask why a rule exists and most prompts cannot answer, because the reason was either never written down or was written into a sentence that got edited three times by people fixing the wording of the rule. A @@ note survives that, since nobody rewrites a comment while tightening an obligation, and it is the artifact an auditor actually wants: not the rule, which they can read, but the decision behind it. The rules in this post are ordinary enough that the reasons look obvious. The ones in your file are not, and the day somebody proposes raising three sentences to five is the day you find out whether the reason was ever recorded anywhere that outlived the person who knew it.