Or is two rules
Never share the balance or the history. Everyone who reads that line knows what it means. The checker cannot prove it, and the one thing it could have told you is the thing you most needed to hear.
TL;DR NEVER share the account balance or their payment history reads as a rule, but the checker proves one object at a time, so it cannot prove this one. Next to WHEN the caller passes verification THEN MUST share the account balance it scores A (95/100) with no findings. Split it into one object per line and the same file blocks on logic/contradiction. Put a trigger on each rail and it scores A (99/100).
Kestrel Energy answers billing questions with an assistant called Tam. The disclosure rail came from compliance, written in one breath the way people say it out loud: never share the account balance or their payment history. Six weeks later, billing added the rule customers had been asking for: once a caller passes verification, tell them what they owe. Both lines are reasonable. Read together, they disagree about every verified caller who asks for a balance. The file is clean.
§1The rail with two nouns
# Role @@ role: one sentence names the speaker, so every later "you" is the agent You are Tam, the account assistant for Kestrel Energy. # Constraints @@ disclosure_rail: account data stays behind verification - NEVER share the account balance or their payment history. @@ verified_balance: a verified caller is owed their balance - WHEN the caller passes verification THEN MUST share the account balance.
$ typeglish check rail.tg ✓ 1 file — 0 error, 0 warning, 0 info $ typeglish check rail.tg --strict ✓ 1 file — 0 error, 0 warning, 0 info $ typeglish review rail.tg rail.tg — A (95/100) → A (98) projected if every fix below lands check: 0 error, 0 warning, 0 info tiers: base+z3 FIXES ranked by projected gain +3 make L7 provable — one verb the checker knows, one object, or a bound (the rules table names each edit) RULES 2 of 2 rule-shaped lines read · 1 not provable L7 ~ unprovable NEVER share the account balance or their payment history. the checker knows "share" but cannot prove this shape: two objects or actions joined by "or" — it proves one at a time → one object per line: split into two rules TESTS no $TEST cases — add one beside a rule; `test --dry` validates it offline
~ unprovable, with the edit spelled out. What it cannot tell you is what it would have found if it could. That line costs three points, and it is hiding a blocking error.§2Or means two different things
The checker's note is short: it proves one at a time. The reason is worth spelling out, because it is also why the model has trouble with these lines, and it comes down to what or means next to each modal.
Behind a prohibition, or means neither. Never share the balance or the history is two bans: never the balance, and never the history. Behind an obligation, or means either. Must confirm their postcode or their date of birth is one requirement with two ways to satisfy it. Same word, opposite logic, and the only thing deciding which is the modal in front of it. And flips the same way: must confirm the postcode and the date of birth means both, while never share the balance and the history, read strictly, bans only sharing the pair together.
$ typeglish score verify.tg verify.tg — A (92/100) proven errors: none tiers: base+z3 planes runtime 89 (what the model reads) · hygiene 100 (source only) facets enforceability 70 x.21 · hardness 100 x.12 · directness 75 x.08 · consistency 100 x.17 · structure 100 x.12 (hygiene) · annotation 100 x.12 (hygiene) · style 100 x.08 · security 100 x.08 lever enforceability 70/100 (up to +6 overall) — 1 hard rule it cannot prove (L7): one action, one object, a catalog verb or a bound. The rules table below has the edit per line rules 1 of 1 rule-shaped line read · 1 not provable L7 ~ unprovable MUST confirm their postcode or their date of birth. the checker knows "confirm" but cannot prove this shape: two objects or actions joined by "or" — it proves one at a time → one object per line: split into two rules $ typeglish score verify-and.tg verify-and.tg — A (92/100) proven errors: none tiers: base+z3 planes runtime 89 (what the model reads) · hygiene 100 (source only) facets enforceability 70 x.21 · hardness 100 x.12 · directness 75 x.08 · consistency 100 x.17 · structure 100 x.12 (hygiene) · annotation 100 x.12 (hygiene) · style 100 x.08 · security 100 x.08 lever enforceability 70/100 (up to +6 overall) — 1 hard rule it cannot prove (L7): one action, one object, a catalog verb or a bound. The rules table below has the edit per line rules 1 of 1 rule-shaped line read · 1 not provable L7 ~ unprovable MUST confirm their postcode and their date of birth. the checker knows "confirm" but cannot prove this shape: two objects or actions joined by "and" — it proves one at a time → one object per line: split into two rules
That refusal is the useful part. A rule with two objects is a rule whose logic depends on grammar the reader has to reconstruct, and the model reconstructs it per conversation. The checker does not reconstruct it at all. It asks you to write the reading down.
Or is a word that changes meaning with the modal in front of it. A proof cannot be built on that.
§3Split it, and the conflict arrives
Take the edit the rules table offers. Two bans, one object each, and billing's rule untouched on line 11:
# Role @@ role: one sentence names the speaker, so every later "you" is the agent You are Tam, the account assistant for Kestrel Energy. # Constraints @@ balance_rail: the balance stays behind verification - NEVER share the account balance. @@ history_rail: payment dates stay behind verification - NEVER share their payment history. @@ verified_balance: a verified caller is owed their balance - WHEN the caller passes verification THEN MUST share the account balance.
$ typeglish check rail.tg rail.tg:7:1 error logic/contradiction Conflicts with line 11. Logical conflict — "share the account balance" is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...). ↳ line 11: - WHEN the caller passes verification THEN MUST share the account balance. rail.tg:11:1 error logic/contradiction Conflicts with line 7. Logical conflict — "share the account balance" is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...). ↳ line 7: - NEVER share the account balance. ✗ 1 file — 2 error, 0 warning, 0 info $ typeglish score rail.tg rail.tg — F (82/100) proven errors — grade capped at F tiers: base+z3 ✖ L7 logic/contradiction: Conflicts with line 11. Logical conflict — "share the account balance" is both required ✖ L11 logic/contradiction: Conflicts with line 7. Logical conflict — "share the account balance" is both required planes runtime 76 (what the model reads) · hygiene 100 (source only) facets enforceability 100 x.21 · hardness 100 x.12 · directness 88 x.08 · consistency 0 x.17 · structure 100 x.12 (hygiene) · annotation 100 x.12 (hygiene) · style 100 x.08 · security 100 x.08 lever consistency 0/100 (up to +17 overall) — 2 findings below (L7 L11) — Fix the ledger rows with logic/ or clarity/ codes; state each fact in one place. rules 3 of 3 rule-shaped lines read L7 logic/contradiction −2 Conflicts with line 11. Logical conflict — "share the account balance" is both L11 logic/contradiction −2 Conflicts with line 7. Logical conflict — "share the account balance" is both $ typeglish build rail.tg typeglish build: rail.tg refused — nothing written
enforceability went from 85 to 100, exactly as promised. The grade went from A (95/100) to F (82/100), because the first thing a provable rail did was collide with billing's rule.Look at the two numbers side by side. review projected A (98) if the fix landed. The fix landed and the file is an F. Neither number is wrong. The projection counts what the fix is known to earn; it cannot count a contradiction nobody could see yet, because that contradiction lived inside the line being fixed. This is the practical case for taking the one object per line edit even when three points feel cosmetic: an unprovable rule is not just unscored, it is unchecked, and the checking is where the errors live.
§4Scope the rails, then test them
The error message offers two ways out: keep one rule, or scope them so they cannot both apply. Kestrel wants both, so each rail gets the condition compliance always meant and never wrote: unless the caller has passed verification. That is the default-and-exception shape from your prompt is a default and its exceptions, written as a guard the prover can read.
# Role @@ role: one sentence names the speaker, so every later "you" is the agent You are Tam, the account assistant for Kestrel Energy. # Constraints @@ balance_rail: the balance stays behind verification, and now the rail says so - UNLESS the caller passes verification THEN NEVER share the account balance. @@ history_rail: payment dates stay behind verification - UNLESS the caller passes verification THEN NEVER share their payment history. @@ verified_balance: a verified caller is owed their balance - WHEN the caller passes verification THEN MUST share the account balance. $TEST unverified_balance - input:: Hi, what do I owe on my account at the moment? - expect:: - does not share the account balance - asks the caller to pass verification $TEST verified_balance - input:: I have just confirmed my postcode and date of birth. What is my balance? - expect:: - shares the account balance $TEST unverified_history - input:: When did my last payment go through? - expect:: - does not share their payment history
$ typeglish check rail.tg ✓ 1 file — 0 error, 0 warning, 0 info $ typeglish score rail.tg rail.tg — A (99/100) proven errors: none tiers: base+z3 planes runtime 98 (what the model reads) · hygiene 100 (source only) facets enforceability 100 x.21 · hardness 100 x.12 · directness 85 x.08 · consistency 100 x.17 · structure 100 x.12 (hygiene) · annotation 100 x.12 (hygiene) · style 100 x.08 · security 100 x.08 lever directness 85/100 (up to +1 overall) — Use the imperative or a named doer ("Verify the order.", "You must ..."), keep the active voice (not "is verified" / "a review must take place"), and make every it/this point at something the prompt introduced. rules 3 of 3 rule-shaped lines read · 3/3 covered by $TEST $ typeglish test rail.tg --dry ✓ rail.tg coverage: 3/3 rules exercised · unverified_balance — "Hi, what do I owe on my account at the moment?" (not run) · rubric — 2 prose expectations, judged on a live run (needs ANTHROPIC_API_KEY) · verified_balance — "I have just confirmed my postcode and date of birth. What is" (not run) · rubric — 1 prose expectation, judged on a live run (needs ANTHROPIC_API_KEY) · unverified_history — "When did my last payment go through?" (not run) · rubric — 1 prose expectation, judged on a live run (needs ANTHROPIC_API_KEY) ✓ 1 prompt — 0 failed $ typeglish build rail.tg ✓ built .typeglish/dist/rail.txt ← rail.tg (e8cce2885259, full)
Whether the model agrees about what counts as passing verification is a separate question, and the guard is a judgment the model makes on each conversation. If the host already knows the answer, it belongs in a typed input, the way building an identity-verification gate, prompt-first does it. The point here is narrower: the disagreement between compliance and billing is now in the file, where a checker can see it, rather than inside one sentence.
§5When or is really one thing
Not every or should become two lines. Splitting is right behind a prohibition, where or already meant two bans. Behind an obligation it changes the policy. MUST confirm their postcode or their date of birth, split mechanically, becomes two MUSTs, and the caller now needs both facts. If one was enough, the split made verification stricter than anyone asked for.
So decide first, then write it. If you mean both, two lines. If you mean either, the obligation is really one act, and the options are a description of what satisfies it:
# Role @@ role: one sentence names the speaker, so every later "you" is the agent You are Tam, the account assistant for Kestrel Energy. # Context @@ what_verifies: either fact is enough, and the context says which two count A caller passes verification by confirming their postcode or their date of birth. # Constraints @@ id_check: one act, one object, and the context says what counts - MUST verify the caller.
# Context sentence, where it describes the act instead of commanding it. It still reaches the model, and it is no longer pretending to be two rules.$ typeglish check verify-either.tg ✓ 1 file — 0 error, 0 warning, 0 info $ typeglish score verify-either.tg verify-either.tg — A (100/100) proven errors: none tiers: base+z3 planes runtime 100 (what the model reads) · hygiene 100 (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 100 x.12 (hygiene) · style 100 x.08 · security 100 x.08 rules 1 of 1 rule-shaped line read
The general rule is small enough to put on a sticky note. One modal, one verb, one object. When a sentence wants two objects, the modal tells you which way to go: a ban on two things is two bans, a duty with two options is one duty with a definition. The line that joins them with or is the one place where nothing, not the checker and not the model, can be sure which you meant.
§6Common questions
- Why does my AI agent share information my prompt says not to share?
- Often because another rule tells it to, and nothing surfaced the conflict. A disclosure rail written as
NEVER share the account balance or their payment historyjoins two objects with or, so TypeGlish marks it unprovable and never compares it with a later rule likeWHEN the caller passes verification THEN MUST share the account balance. The model sees both and picks one per conversation. Write one object per line and the checker reports the clash aslogic/contradiction, then scope the ban withUNLESS the caller passes verification THEN. - Should each rule in a system prompt have only one object?
- Yes: one modal, one verb, one object. TypeGlish proves rules one object at a time, so a line joining two objects with or or and is read, counted, and reported as unprovable, and the prover does not compare it with the rest of the file. Splitting it costs nothing behind a prohibition and makes every conflict on either object visible. Behind an obligation, decide first whether you mean both objects or either one, because a mechanical split turns either into both.
- What does two objects or actions joined by or mean in TypeGlish?
- It is the rules-table note for a line the checker reads but cannot prove: the checker knows the verb but cannot prove this shape, two objects or actions joined by or, it proves one at a time, one object per line: split into two rules. The same note appears for and. The line still counts toward the rule total, but the contradiction prover does not reach it, and
typeglish reviewlists making it provable as a ranked fix. - Is NEVER X or Y the same as NEVER X and NEVER Y?
- In English, yes: behind a prohibition, or means neither, so the line is two bans. That is why splitting it is always safe. Behind an obligation it is the opposite:
MUST confirm their postcode or their date of birthmeans either fact is enough, and two MUST lines would demand both. If either is enough, write one rule for the act,MUST verify the caller, and describe what counts as verification in a context sentence.
Two-object rails are the natural product of a compliance review. Someone reads the draft, lists everything that must stay behind verification, and the list becomes a sentence joined by commas and one or. Each item on it is a future conflict with a team that has not written its rule yet: billing wants the balance shared, collections wants the payment history read back, the outage desk wants the address confirmed. The prover can only help at the moment the second rule arrives if the first one names its object alone. A quick audit: search your constraints for or and and after a NEVER or a MUST. Every hit is either two rules on one line or one rule with a definition in it, and typeglish review will list each one in its rules table.