> Markdown rendition of https://typeglish.dev/blog/condition-last-ablation ("We put the condition last. The checker stopped defending the rule. - Tidelines"). Canonical page: https://typeglish.dev/blog/condition-last-ablation · All pages: https://typeglish.dev/llms.txt

[← Tidelines](https://typeglish.dev/blog)/ Deep dives Sep 30, 2026

# We put the condition last. The checker stopped defending the rule.

English lets you put the *when* at either end of a sentence, and most people put it last. We took a clean car-hire agent, moved the condition to the end of each of its seven guarded rules in turn, and then tried to sneak a contradiction past every one of them.

by **TypeGlish team** 7 min read #deep-dives

Condition last, rule undefended.

**TL;DR** `WHEN the customer accepts a quoted extension price THEN MUST call @[extend_rental]` and `MUST call @[extend_rental] once the customer accepts a quoted extension price` read as the same rule, but only the first is one the checker can prove. Move all seven conditions in a clean prompt to the end of their lines and it still grades A (93/100); add a rule that contradicts one of them and the build that used to be refused now passes clean at A (94/100). Write the condition first, and gate on the rules table, not the grade.

Nobody writes *WHEN the customer asks for a human THEN MUST transfer the chat* in a first draft. They write *transfer the chat to a live agent if the customer asks for a human*, because that is how people give instructions to people. The condition trails the action, the way it does in a policy document, a training manual, or a message from ops. This run measures what that one habit costs: the same seven rules, condition first and condition last, each put through `check`, `score` and `build`, and then each one put up against an edit that contradicts it.

## §1 The baseline

A chat assistant for a car-hire company: two tools, one length bound, seven guarded rules. Every guard sits at the head of its line, in the shape the language reference teaches.

base.tg - a car-hire support agent, seven guarded rules ✓ A (99/100)

```typeglish
$TOOL find_booking
  - description:: Find a rental booking by its reference.
  - input::
    - reference:: string: the booking reference.

$TOOL extend_rental
  - description:: Extend an active rental by a number of days.
  - input::
    - reference:: string: the booking reference.
    - days:: integer between 1 and 14: the extra days.

# Role
@@ role: one chat assistant for rental customers, with hard rails on money and safety
You are Mira, the chat support assistant for Tolland Car Hire.

# Constraints
@@ brevity: three sentences fits a phone screen at a rental desk
- MUST keep every reply to at most 3 sentences.
@@ lookup: never answer about a booking from memory
- WHEN the customer gives a booking reference THEN MUST call @[find_booking].
@@ extension_consent: the extension charges a card, so it waits for a yes
- WHEN the customer accepts a quoted extension price THEN MUST call @[extend_rental].
@@ accident_first: safety comes before paperwork
- IF the customer reports an accident THEN MUST ask whether anyone needs medical help.
@@ breakdown: the roadside line is the fastest fix for a stranded driver
- WHEN the customer reports a breakdown THEN MUST share our roadside assistance number.
@@ damage_dispute: a disputed charge is a claims decision, not a chat one
- IF the customer disputes a damage charge THEN escalate to our claims team.
@@ fuel_reminder: an empty tank costs the customer a refuelling fee
- UNLESS the booking includes prepaid fuel THEN MUST remind the customer to return the car with a full tank.
@@ human: a request for a person is always honoured
- WHEN the customer asks for a human THEN MUST transfer the chat to a live agent.
```

Seven guarded rules on lines 20 to 32, one bound on line 18. The `@@` notes are stripped before the model reads anything; they are here so the file grades on its rules, not on its hygiene.

tg check, score and build - base.tg

```
$ npx typeglish check base.tg
✓ 1 file — 0 error, 0 warning, 0 info

$ npx typeglish score base.tg
base.tg — A (99/100)  proven errors: none  tiers: base+z3
  planes  runtime 99 (what the model reads) · hygiene 100 (source only)
  facets  enforceability 100 x.21 · hardness 100 x.12 · directness 91 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   8 of 8 rule-shaped lines read

$ npx typeglish build base.tg
✓ built .typeglish/dist/base.txt ← base.tg (c01009d6dd33, full)
```

Eight of eight lines read, enforceability 100. Every rule in the file is one the prover holds.

## §2 Seven moves

Each variant is `base.tg` with exactly one rule rewritten: the guard comes off the front and goes on the end, joined by the word a person would actually use. Nothing else changes, not the verb, not the object, not the modal. The one exception to "not the modal" is the claims line, which never had one: *THEN escalate* is a bare catalog imperative after `THEN`, so the trailing version is *Escalate to our claims team if...*, which is how it would be written anyway.

the results - one rule moved per variant ✓ 7 of 7 pass

```
# rule moved          joined by   check                     grade        enforceability
lookup              when        clean                     A (99/100)   96
extension_consent   once        clean                     A (99/100)   96
accident_first      if          clean                     A (99/100)   96
breakdown           when        clean                     A (99/100)   96
damage_dispute      if          info prompt/unparsed-rule   A (98/100)   94
fuel_reminder       unless      clean                     A (99/100)   96
human               when        clean                     A (99/100)   96
# all seven at once
all-moved           -           info prompt/unparsed-rule   A (93/100)   68
```

Six of the seven moves leave the grade exactly where it was. The worst single move costs one point. All seven together cost six, and the file is still an A.

Read that as the scorer working correctly, not failing. The trailing version of a rule is still a rule: it has a modal, a catalog verb and an object, so it counts as read. What it loses is the *proof*, and the proof share is one of three inside one facet, so one unprovable line out of eight moves the grade by a rounding error. The facet that cares is enforceability, and even there the drop from 100 to 96 is the kind of number people stop looking at.

The one move that draws a finding is the one with no modal. *Escalate to our claims team if the customer disputes a damage charge* is read as prose, and the checker says so at info. The six lines that kept their `MUST` draw nothing at all.

## §3 The edit that should have failed

A grade that barely moves would be fine if nothing else moved either. So the second half of the run adds the kind of line that turns up in a prompt three months later: a fleet shortage, extensions paused, and somebody in ops adds one rule at the top of the section.

the later edit - added above the brevity rule

```
@@ fleet_shortage: extensions paused while the fleet is short
- NEVER call @[extend_rental].
```

That line contradicts the consent rule: the moment a customer accepts an extension price, the prompt both requires and forbids the call. Against the baseline, the compiler says exactly that and refuses to build. Against the all-moved file, it says nothing.

tg check and build - the same edit, both files ✗ one refused, one shipped

```
$ npx typeglish check base-plus-edit.tg
base-plus-edit.tg:18:1  error  logic/contradiction  Conflicts with line 24. Logical conflict — "call
  @[extend_rental]." is both required and forbidden. Keep one, or scope the two rules so
  they cannot both apply (IF <condition> THEN ...).
                   ↳ line 24: - WHEN the customer accepts a quoted extension price THEN MUST call @[extend_rental].

✗ 1 file — 2 error, 0 warning, 0 info

$ npx typeglish build base-plus-edit.tg
typeglish build: base-plus-edit.tg refused — nothing written

$ npx typeglish check moved-plus-edit.tg --strict
moved-plus-edit.tg:30:1  info   prompt/unparsed-rule  Reads like a rule, but the rule reader cannot
  parse it as one, ...

✓ 1 file — 0 error, 0 warning, 1 info

$ npx typeglish score moved-plus-edit.tg
moved-plus-edit.tg — A (94/100)  proven errors: none  tiers: base+z3

$ npx typeglish build moved-plus-edit.tg
✓ built .typeglish/dist/moved-plus-edit.txt ← moved-plus-edit.tg (77f60546e5e7, full)
```

The contradicted file exits 0 under `--strict`, builds, and grades a point *higher* than it did before the contradiction arrived: the new `NEVER` is a clean provable rule, so it raises the proof share it is quietly breaking. The one info line is the claims rule from §2, not the conflict.

We ran the same test against each rule alone: a one-move variant, plus a `NEVER` that negates that rule's action. The result has no exceptions.

the results - each rule against an edit that contradicts it ✗ 0 of 7 defended

```
# rule                the contradicting edit                          condition first            condition last
lookup              NEVER call @[find_booking].                     logic/contradiction F   clean A (99)
extension_consent   NEVER call @[extend_rental].                    logic/contradiction F   clean A (99)
accident_first      NEVER ask whether anyone needs medical help.    logic/contradiction F   clean A (99)
breakdown           NEVER share our roadside assistance number.     logic/contradiction F   clean A (99)
damage_dispute      NEVER escalate to our claims team.              logic/contradiction F   clean A (98)
fuel_reminder       NEVER remind the customer to return the car...  logic/contradiction F   clean A (99)
human               NEVER transfer the chat to a live agent.        logic/contradiction F   clean A (99)
```

Condition first, every contradiction is caught and every build refused at F (83/100). Condition last, every one ships, at the grade the file had before the edit. The fuel line is the one to look at twice: *MUST remind ... unless the booking includes prepaid fuel* is the most natural sentence in the file.

Stripped to the two lines that matter, the pair is small enough to run yourself. Same tool, same rule, same prohibition; the only difference is where the condition sits.

pair-lead.tg - condition first ✗ logic/contradiction

```typeglish
$TOOL extend_rental
  - description:: Extend an active rental by a number of days.
  - input::
    - reference:: string: the booking reference.
    - days:: integer between 1 and 14: the extra days.

# Role
You are Mira, the chat support assistant for Tolland Car Hire.

# Constraints
- WHEN the customer accepts a quoted extension price THEN MUST call @[extend_rental].
- NEVER call @[extend_rental].
```

pair-trail.tg - condition last ✓ clean, B (84/100)

```typeglish
$TOOL extend_rental
  - description:: Extend an active rental by a number of days.
  - input::
    - reference:: string: the booking reference.
    - days:: integer between 1 and 14: the extra days.

# Role
You are Mira, the chat support assistant for Tolland Car Hire.

# Constraints
- MUST call @[extend_rental] when the customer accepts a quoted extension price.
- NEVER call @[extend_rental].
```

The first grades F (70/100) with two blocking errors; the second checks clean with 0 error, 0 warning, 0 info and grades B (84/100). The model receives the same obligation and the same prohibition either way. Only one of the two files told anybody.

## §4 Where the reader stops

None of this is hidden. The rules table in `score` names every line the prover cannot hold, and for the trailing rules it names the exact word it stopped at.

tg score - the rules table for all-moved.tg (three of seven rows)

```
$ npx typeglish score all-moved.tg
all-moved.tg — A (93/100)  proven errors: none  tiers: base+z3
  ...
  rules   7 of 8 rule-shaped lines read · 6 not provable
    L20  ~ unprovable    MUST call @[find_booking] when the customer gives a booking reference.
                         the checker knows "call" but cannot prove this shape: it stops reading at "when" — the
                         clause after it is not part of the provable action → if the clause is a condition, make it
                         one: WHEN <clause> THEN MUST <verb> …; otherwise give it its own rule
    L22  ~ unprovable    MUST call @[extend_rental] once the customer accepts a quoted extension price.
                         the checker knows "call" but cannot prove this shape: the object runs past six words → name
                         the object in fewer words, or split the rule
    L30  ~ unprovable    MUST remind the customer to return the car with a full tank unless the booking includes prepaid
                         the checker knows "remind" but cannot prove this shape: it stops reading at "unless" — the
                         clause after it is not part of the provable action → if the clause is a condition, make it
                         one: WHEN <clause> THEN MUST <verb> …; otherwise give it its own rule
```

Two different failures under one mark. *When*, *if* and *unless* are clause words the reader recognises and stops at. *Once* is not: the reader carries on, swallows the whole tail as the object of *call*, and gives up because the object is too long.

Both failures come to the same thing. A contradiction check is a comparison between two rules' actions, and a rule the prover cannot hold has no action to compare. The trailing clause is not treated as a condition that narrows the rule, and it is not ignored so the rule reads as unconditional either. Either of those would have produced a finding against `NEVER call @[extend_rental]`. The line is simply taken out of the comparison, which is the one outcome that produces silence.

That is the same shape as two earlier runs from the other direction. When we [took the scope off every rule](https://typeglish.dev/blog/guard-scope-ablation), the condition vanished and some rules started conflicting that should not; here the condition survives in the sentence and the rule stops conflicting with anything. And when we [softened MUST to SHOULD](https://typeglish.dev/blog/deontic-force-ablation), the rule did not get marked down, it dropped out of what gets measured. A trailing condition does the same thing without touching the modal, which is why nobody reviewing the diff would think the rule had got weaker.

> The model reads both sentences as the same rule. Only one of them is a rule anything else can argue with.

## §5 Condition first, and what to gate on

The fix is mechanical, and `review` ranks it for you: on `all-moved.tg` its top fix is *make L20 L22 L24 L26 L30 L32 provable*, worth +5, with the rules table naming the rewrite for each line. Put the guard back at the front (`WHEN`, `IF` or `UNLESS`, then `THEN`, then the modal) and the file is `base.tg` again.

Once the condition is in front, the fleet-shortage edit is refused, and that refusal is the useful part: it forces the decision nobody made. The prompt cannot both take extensions and not take them. If the shortage is a state the business switches on and off, it is an input, and the compiler can keep exactly one of the two rules in each deployed prompt.

fixed.tg - the shortage as a typed switch ✓ A (100/100)

```typeglish
$REQUIRE variable extensions: one of open, paused

$TOOL extend_rental
  - description:: Extend an active rental by a number of days.
  - input::
    - reference:: string: the booking reference.
    - days:: integer between 1 and 14: the extra days.

# Role
@@ role: one chat assistant for rental customers, with hard rails on money and safety
You are Mira, the chat support assistant for Tolland Car Hire.

# Constraints
@@ extensions: ops sets the switch per deploy; a paused fleet takes no new days
$IF @{extensions} is equal to open:
  - WHEN the customer accepts a quoted extension price THEN MUST call @[extend_rental].
$ELSE:
  - NEVER call @[extend_rental].
```

tg build - one artifact per state ✓ two builds

```
$ npx typeglish build fixed.tg --vars '{"extensions":"paused"}'
✓ built .typeglish/dist/fixed.txt ← fixed.tg (c4c8fce821d4, full)

$ tail -1 .typeglish/dist/fixed.txt
- NEVER call extend_rental.

$ npx typeglish build fixed.tg --vars '{"extensions":"open"}'
✓ built .typeglish/dist/fixed.txt ← fixed.tg (854467d6ddca, full)

$ tail -1 .typeglish/dist/fixed.txt
- WHEN the customer accepts a quoted extension price THEN MUST call extend_rental.
```

The losing arm never reaches the model, so neither deployed prompt contains a contradiction, and nobody has to rely on the model picking the right one of two rules.

Then gate on the right number. The grade is the wrong one for this: six of seven moves did not change it, and all seven together left an A. What does change, every time, is the rules table. `review` lists each `~ unprovable` line with its line number and the edit, and `score --json` carries the same line numbers in the enforceability facet, under `members.notProvable`, so a CI step can require that list to be empty. That is a stricter gate than a grade floor and a much cheaper one than finding the contradiction in a transcript. The same "a comma is not a THEN" lesson, from the other end of the sentence, is in [the starter prompt that came with the platform](https://typeglish.dev/blog/teardown-starter-prompt).

## §6 Common questions

**Is MUST do X when Y the same rule as WHEN Y THEN MUST do X?**

To a reader, yes. To the checker, no. WHEN Y THEN MUST do X is a guarded rule it can prove against every other rule in the file. MUST do X when Y is read as a rule, but the reader stops at when, so the rule is marked unprovable in the rules table and takes part in no contradiction check. In this ablation all seven guarded rules of a car-hire agent survived the move with a clean check and an A, and all seven stopped catching a contradicting edit.

**Why did my prompt pass the check when two of its rules contradict each other?**

One likely reason is that one of the two rules keeps its condition at the end of the line. Here, NEVER call @[extend_rental] beside WHEN the customer accepts a quoted extension price THEN MUST call @[extend_rental] is a blocking logic/contradiction and the build is refused. Beside MUST call @[extend_rental] once the customer accepts a quoted extension price, the same pair checks clean, exits 0 even with --strict, and grades A (94/100). Run typeglish score and read the rules table: every line marked ~ unprovable is a rule no conflict can be proven against.

**Which words at the end of a rule stop the checker reading it?**

In this run the rules table named when, if and unless as the place it stops reading, with the edit to make the clause a condition. Once was not treated as a clause boundary at all: the whole tail was read as the object, and the line failed as an object that runs past six words. Either way the rule is unprovable. The reference names before, after and unless as trailing clauses to turn into conditions.

**How do I stop trailing conditions getting into an agent prompt?**

Write the condition first, WHEN or IF or UNLESS, then THEN, then the modal, and gate on the rules table rather than the grade. Moving one condition to the end cost at most one point here, and moving all seven still graded A (93/100), so a grade floor will not catch it. typeglish review lists every unprovable line with its line number and the rewrite, and score --json carries the same line numbers in the enforceability facet, under members.notProvable, which a CI step can require to be empty.

Field note

Trailing conditions are not a beginner's mistake; they are what a prompt looks like after it has been through the business. Ops writes *pause extensions until the new cars arrive*. Legal writes *do not discuss liability unless a claim number has been issued*. A team lead pastes the escalation matrix in the order it appears on the wiki: action first, trigger second. Every one of those lines reads fine to the model and to the reviewer, and every one of them is a rule the checker quietly stops comparing. The grade will not tell you. The rules table will, line by line, and it is one command: `npx typeglish score`. Read it on every import, and read it again on every edit somebody else made to your prompt.

∿ washed up Sep 30, 2026 ∿
