> Markdown rendition of https://typeglish.dev/blog/money-symbol-not-a-bound ("$40 and 40 dollars are not the same rule - Tidelines"). Canonical page: https://typeglish.dev/blog/money-symbol-not-a-bound · All pages: https://typeglish.dev/llms.txt

[← Tidelines](https://typeglish.dev/blog)/ Best practices Sep 18, 2026

# $40 and 40 dollars are not the same rule

Two rules about one credit, provably impossible together, and the file grades A (100/100). One character in each line is the reason, and it is the character every prompt writer on earth types when they mean money.

by **TypeGlish team** 8 min read #best-practices

The number nothing counted.

**TL;DR** A currency symbol keeps the amount out of the arithmetic: `at most $40` beside `at least $75` checks clean at `A (100/100)` with `consistency 100`, and the identical policy written `at most 40 dollars` and `at least 75 dollars` is two blocking `logic/numeric` errors at `F (83/100)`. Write money as a number and a unit word.

Halbrook Mobile is a mid-sized network with a care desk of about sixty people. Their chat agent handles bill queries, and the one thing it is allowed to give away is a goodwill credit. In March, finance set the ceiling and somebody wrote it into the prompt. In September, after two days of network trouble in the north west, the outage playbook was pasted into the same section. Both lines are still there. The checker has never had anything to say about either of them.

## §1 Two ceilings, one desk, one green check

Here is the section, annotated, eleven lines, the way a careful team writes it. Read lines 7 and 9 together.

goodwill.tg - a floor above a ceiling ✓ A (100/100)

```typeglish
# Role
@@ role: the desk this file speaks for
You are Vale, the billing assistant for Halbrook Mobile.

# Goodwill
@@ desk_cap: the care desk limit finance signed off in March
- MUST approve a credit of at most $40.
@@ outage_floor: from the outage playbook, pasted in last Tuesday
- MUST approve a credit of at least $75.
@@ brevity: two sentences keeps a billing reply scannable
- MUST keep every reply to at most 2 sentences.
```

No credit satisfies both. There is no amount that is at most forty and at least seventy-five, and this is exactly the class of defect TypeGlish exists to refuse. Run it.

tg check, --strict and score - goodwill.tg ✗ nothing about the money

```
$ typeglish check goodwill.tg
✓ 1 file - 0 error, 0 warning, 0 info

$ typeglish check goodwill.tg --strict
✓ 1 file - 0 error, 0 warning, 0 info

$ typeglish score goodwill.tg
goodwill.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   3 of 3 rule-shaped lines read
```

A perfect score. Not a warning, not an info, no lever left to pull, and `3 of 3 rule-shaped lines read` says the checker believes it understood every rule in the file. `consistency 100` is the one to sit with: that facet is the answer to *did anything here collide*, and it is reporting on a comparison that never happened.

Now change two characters. Nothing else: same modal, same verb, same object, same amounts, same annotations.

goodwill-words.tg - the same two amounts, spelled out ✗ F (83/100)

```typeglish
# Role
@@ role: the desk this file speaks for
You are Vale, the billing assistant for Halbrook Mobile.

# Goodwill
@@ desk_cap: the care desk limit finance signed off in March
- MUST approve a credit of at most 40 dollars.
@@ outage_floor: from the outage playbook, pasted in last Tuesday
- MUST approve a credit of at least 75 dollars.
@@ brevity: two sentences keeps a billing reply scannable
- MUST keep every reply to at most 2 sentences.
```

tg check and score - goodwill-words.tg ✗ exit 1, build refused

```
$ typeglish check goodwill-words.tg
goodwill-words.tg:7:1  error  logic/numeric  Conflicts with line 9. Numeric conflict -
  "at most 40 dollars" and "at least 75 dollars" can't both hold.
                   ↳ line 9: - MUST approve a credit of at least 75 dollars.
goodwill-words.tg:9:1  error  logic/numeric  Conflicts with line 7. Numeric conflict -
  "at most 40 dollars" and "at least 75 dollars" can't both hold.
                   ↳ line 7: - MUST approve a credit of at most 40 dollars.

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

$ typeglish score goodwill-words.tg
goodwill-words.tg - F (83/100)  proven errors - grade capped at F  tiers: base+z3
  planes  runtime 78 (what the model reads) · hygiene 100 (source only)
  facets  enforceability 100 x.21 · hardness 100 x.12 · directness 100 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 L9)
```

Same policy, same two impossible lines, and the grade goes from the top of the scale to a refused build. The interesting direction is the one nobody expects: the version a reviewer would call tidier, with the crisp `$40`, is the one that ships.

## §2 What the numeric layer is actually looking for

The money layer wants a quantity and a unit, and the unit has to be a word. *40 dollars* is a number with a unit attached, so it lowers into an interval the prover can intersect with every other interval on the same slot. *$40* is a number with a piece of punctuation in front of it, and punctuation is not a unit. The amount reaches the model perfectly well and reaches the arithmetic not at all.

Six spellings of one impossible pair, each file a Role line and the two rules, nothing else changed:

tg check and score - six ways to write a ceiling and a floor ✗ three of six are silent

```
  at most ...          at least ...         check      score
  40 dollars           75 dollars           2 error    F (71/100)
  40 pounds            75 pounds            2 error    F (71/100)
  40 USD               75 USD               4 error    F (71/100)

  $40                  $75                  clean      B (87/100)
  $40 dollars          $75 dollars          clean      B (81/100)
  40                   75                   clean      B (87/100)

  # the code form is read twice, as money and as a bare count:
$ typeglish check e.tg
e.tg:5:1  error  logic/contradiction  Conflicts with line 6. Counted rule - "approve a
  credit of at most 40 USD." vs "approve a credit of at least 75 USD." is bound to at
  most 40 but at least 75. The counts cannot both hold.
e.tg:5:1  error  logic/numeric  Conflicts with line 6. Numeric conflict - "at most 40 USD"
  and "at least 75 USD" can't both hold.
```

Read the last row before you conclude this is about currency. A bare `40` against a bare `75`, no unit at all, is also clean, which tells you the rule is not *symbols are unsupported* but *the unit is what puts the number in the money slot*. The middle row is the cruel one: adding the word *dollars* after the symbol reads to a human as belt and braces, and proves nothing.

> A currency symbol tells the model what the number means. The unit word is what tells the prover.

Pounds, euros, cents and pence behave exactly as dollars do, because the checker is matching a unit word rather than recognising a currency. The three-letter codes work too, twice over: `40 USD` is read as money and also as a bare count, so the same conflict reports under `logic/numeric` and `logic/contradiction` at once. There is one spelling in the whole set with no upside, and it is the one on the keyboard.

## §3 The hint you almost got

There is a version of this file where the toolchain does mutter. Widen the object from *a credit* to *a goodwill credit*, change nothing else, and the score card starts naming lines 7 and 9:

tg score - the same symbols, with a longer object ✗ A (96/100), and still no error

```
$ typeglish score goodwill.tg   # "a goodwill credit of at most $40."
goodwill.tg - A (96/100)  proven errors: none  tiers: base+z3
  facets  enforceability 80 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
  lever   enforceability 80/100 (up to +4 overall) - 2 hard rules it cannot prove
          (L7 L9): one action, one object, a catalog verb or a bound. The rules
          table below has the edit per line
  rules   3 of 3 rule-shaped lines read · 2 not provable
    L7   ~ unprovable    MUST approve a goodwill credit of at most $40.
                         the checker knows "approve" but cannot prove this shape:
                         the object runs past six words
```

Two words longer and the file drops to `A (96/100)` with the exact two lines flagged as unprovable. The diagnosis it offers is about object length, and that diagnosis is not wrong: shorten the object in the words version and it still proves, shorten it in the symbol version and the flag goes away while the conflict stays. The signal is real and it is pointing at the wrong thing, so treat `~ unprovable` on a rule with a number in it as a prompt to check the number, not the noun.

This is the part worth internalising, because it generalises past money. `enforceability` is the share of your rule-shaped lines the checker can read and prove, and it is the largest single facet in the grade. A line that reads but does not prove is a line with no opinion attached: it counts toward your rule total, it renders to the model, and it sits out every comparison. [Your bound is for the rule you have not written yet](https://typeglish.dev/blog/bounds-ablation) makes the same argument from the other end, that a bound is a slot the next edit lands in. A bound the prover cannot see is a slot with no floor under it.

## §4 What ships

Two edits. Take the symbol out, which makes the conflict appear, and then resolve the conflict the way the desk would: one ceiling, and a route for anything above it. The outage playbook did not want a second cap, it wanted an exception, and an exception is a rule with a trigger.

goodwill-fixed.tg - one ceiling, in words, and a way past it ✓ A (100/100)

```typeglish
$IMPORT tool open_goodwill_case

# Role
@@ role: the desk this file speaks for
You are Vale, the billing assistant for Halbrook Mobile.

# Goodwill
@@ desk_cap: one ceiling, in words, so the prover holds the number
- MUST approve a credit of at most 40 dollars.
@@ outage_route: the outage playbook asks for more than the desk can give
- WHEN the customer asks for a credit over 40 dollars THEN MUST call @[open_goodwill_case].
@@ brevity: two sentences keeps a billing reply scannable
- MUST keep every reply to at most 2 sentences.

$TEST outage_credit
  - input:: Your network was down for two days. I want 75 dollars off my bill.
  - expect::
    - calls open_goodwill_case
    - at most 2 sentences
```

tg score, test --dry and build - goodwill-fixed.tg ✓ 0 error, 0 warning, 0 info

```
$ typeglish score goodwill-fixed.tg
goodwill-fixed.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 97 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   3 of 3 rule-shaped lines read · 2/3 covered by $TEST

$ typeglish test goodwill-fixed.tg --dry
✓ goodwill-fixed.tg  coverage: 2/3 rules exercised
  uncovered (no case shares the rule's wording):
    L9  approve a credit of at most 40 dollars.
  · outage_credit - "Your network was down for two days. I want 75 dollars off my" (not run)
      ✓ at most 2 sentences

$ typeglish build goodwill-fixed.tg
✓ built .typeglish/dist/goodwill-fixed.txt ← goodwill-fixed.tg (9f89dcff1428, full)

  # Role
  You are Vale, the billing assistant for Halbrook Mobile.

  # Goodwill
  - MUST approve a credit of at most 40 dollars.
  - WHEN the customer asks for a credit over 40 dollars THEN MUST call open_goodwill_case.
  - MUST keep every reply to at most 2 sentences.
```

The same grade as the broken file, earned differently. Note the artifact: `40 dollars` reaches the model as *40 dollars*, which is what you would have written anyway, so the change costs the model nothing and buys you the comparison. `coverage: 2/3` is honest about what the suite pins: the ceiling itself has no case, because a rule about refusing is hard to trigger from one turn.

When the amount genuinely varies per customer, it does not belong in a rule at all. Hand it to the runtime as a typed input and compare it, and the comparison carries no unit to get wrong:

tg build --vars - the threshold on the deterministic plane ✓ one arm ships

```
  $REQUIRE variable credit_asked: number
  $IF @{credit_asked} is at most 40:
    - MUST approve the credit.
  $ELSE:
    - MUST escalate the credit to a human agent.

$ typeglish build runtime.tg --vars '{"credit_asked":75}'
✓ built .typeglish/dist/runtime.txt ← runtime.tg (47c8e0911d35, full)

  # Goodwill
  - MUST escalate the credit to a human agent.
  - MUST keep every reply to at most 2 sentences.
```

The losing arm never reaches the model, so there is no second ceiling in the artifact for a model to average against. That is a different trade from the one [the number in the prompt vs. the number at runtime](https://typeglish.dev/blog/number-in-prompt-vs-runtime) weighs up: a number in the file can be proven against other numbers in the file, and a number at runtime cannot be proven at all, only compared.

## §5 Common questions

**Why does my agent ignore the refund cap in my system prompt?**

One common reason is that the cap was never a number to anything but you. A ceiling written with a currency symbol reaches the model as text and reaches the checker as text, so a second rule that contradicts it is never compared with it. The pair `MUST approve a credit of at most $40` beside `MUST approve a credit of at least $75` is a clean check at `A (100/100)` with `consistency 100`; the same pair written `40 dollars` and `75 dollars` is two blocking `logic/numeric` errors at `F (83/100)`.

**Should I write $50 or 50 dollars in a system prompt?**

Write `50 dollars`. A number followed by a unit word lowers into the money layer, where Z3 can intersect it with every other bound on the same slot. A leading currency symbol stops that, and adding the word after the symbol does not rescue it: `$50 dollars` is still a clean check against a contradicting rule. The symbol is also the one spelling with no upside, because the artifact reads the same either way.

**Does TypeGlish check money amounts in pounds or euros?**

Yes. The unit is a word, not a currency, so `40 pounds`, `40 euros`, `40 cents` and `40 pence` are all proven against a conflicting bound exactly as `40 dollars` is. The three-letter codes work too, and `40 USD` is read twice, once as money and once as a bare count, so a conflict there reports under both `logic/numeric` and `logic/contradiction`. Only the leading symbol is invisible.

**Where should an amount live if it changes per customer?**

In a typed input, compared with an operator rather than stated as a bound. Declare `$REQUIRE variable credit_asked: number` and branch with `$IF @{credit_asked} is at most 40`, and the comparison carries no unit at all: the compiler evaluates the arm and the losing branch never reaches the model. Keep the desk's own ceiling in the file as a rule in words, because that is the number a second author will contradict.

Field note

The audit is one line and you can run it before you finish reading this: `grep -n '[$£€¥]' prompts/*.tg`. Every hit is an amount that is currently prose. Some of them should stay prose, because a price you are quoting inside a literal is copy and not policy. The rest are ceilings, floors, thresholds and fees, and each one is a number some future edit will contradict in a section you are not looking at. Rewriting them costs one word each. The reason this defect survives review so reliably is that `$40` looks *more* precise than *40 dollars* to a human reader, so the spelling that hides the bound is the spelling a careful reviewer prefers, and [a refund limit set twice at two amounts](https://typeglish.dev/blog/agent-refund-cap) is the failure it produces on the floor.

∿ washed up Sep 18, 2026 ∿
