> Markdown rendition of https://typeglish.dev/blog/prompt-arithmetic ("The arithmetic in your prompt - Tidelines"). Canonical page: https://typeglish.dev/blog/prompt-arithmetic · All pages: https://typeglish.dev/llms.txt

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

# The arithmetic in your prompt

Prompts are full of numbers: at most three sentences, at least two options, call one tool. Writers treat them as emphasis. The checker treats them as constraints it can actually solve, which means it can catch the ones that add up to nothing.

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

Every number is a constraint.

**TL;DR** Every number in a prompt is a constraint, not a suggestion. When two of them can't both be true, like *at most 3 sentences* and *at least 5 sentences*, the model quietly satisfies one per reply and the other looks ignored. TypeGlish reads the numbers as real inequalities and proves the conflict at compile time with `logic/numeric`, so you fix it before it ships.

Updated for typeglish 0.10.0

The first version of this post claimed to fix the conflict by guarding only the floor: a flat `MUST keep a routine reply to at most 3 sentences` beside `WHEN explaining the return policy THEN answer in at least 5 sentences`. That was wrong. A flat rule applies to every reply, the returns explanation included, so the two bounds still collided there. typeglish 0.9.0 let it through for two reasons that no longer hold: it did not prove `WHEN` guards, and a bare imperative after `THEN` with no modal was not read as a rule at all. 0.10.0 does both and reports the conflict the file always had. The fix in §3 now carves the exception out of the default with `UNLESS` / `WHEN`, and every figure on this page has been re-run against 0.10.0.

Ask a builder why their agent's replies keep blowing past the length limit and they will usually blame the model. Sometimes that is fair. More often the prompt contains two numbers that cannot both be honored, and the model is doing the only thing it can: picking one, differently, every time. A number in a prompt is not decoration and it is not emphasis. It is a claim about the shape of a valid answer, and like any claim it can be checked, and like any pair of claims it can be inconsistent. Most prompt tools cannot see that far, because to them "at most 3" is just three words. To a checker with a solver behind it, it is an inequality.

## §1 A number is a promise the checker can hold

There are two ways to write a magnitude, and only one of them is checkable. "Keep replies short" names a feeling; nothing can hold the model to it and nothing can hold *you* to it either, which is why it drifts. "Reply in at most 3 sentences" names a bound. The difference is not style. A bound is a value a checker can compare, count against, and reason about; a vibe is invisible to every tool you own. The moment you commit to a number, you have handed the compiler something it can actually work with, including the ability to tell you when you have committed to two numbers that fight.

> A vague magnitude constrains nothing. A precise one can be proven inconsistent. Only one of those is a spec.

## §2 Two limits, one reply

Here is how it happens in real prompts, and it is never on purpose. Someone adds a brevity rule for scannability. Months later, someone else adds a thoroughness rule for the returns flow. Both are sensible. Together they demand a reply that is at most three sentences and at least five, on every message, which is no reply at all.

support.tg ✕ won't compile

```typeglish
# Role
You are a support agent for an online electronics retailer.

# Constraints
@@ brevity: replies over three sentences get skimmed
- MUST keep every reply to at most 3 sentences.
@@ thorough: a returns explanation has to cover the conditions
- MUST answer in at least 5 sentences.
```

Each rule reads perfectly on its own. The defect is only in the pair, and only if you do the arithmetic: there is no whole number of sentences that is both at most 3 and at least 5.

A prose linter cannot catch this, because there is nothing wrong with either sentence. You need something that reads the numbers as numbers. TypeGlish hands both bounds to Z3, its solver, asks whether any value satisfies them at once, and gets back "no." That "no" is a proof, not a heuristic, so it is a blocking error rather than a warning.

tg check - output

```
support.tg:6:1  error  logic/numeric  Conflicts with line 8. Numeric conflict — "at most 3 sentences" and "at least 5 sentences" can't both hold.
            ↳ line 8: - MUST answer in at least 5 sentences.
support.tg:6:1  warn   prompt/count-alignment  Count alignment — "sentence" carries two different count rules (line 8): one names a unit, one does not. Two spellings of one limit read as drift — state ONE bound with ONE unit.
            ↳ line 8: - MUST answer in at least 5 sentences.
support.tg:8:1  error  logic/numeric  Conflicts with line 6. Numeric conflict — "at most 3 sentences" and "at least 5 sentences" can't both hold.
            ↳ line 6: - MUST keep every reply to at most 3 sentences.

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

The checker names both numbers and both lines. It is not guessing that these *might* conflict; it has proven that no answer satisfies both, which is exactly the thing a human review of two far-apart rules almost never does. The warning between them is a separate check, `prompt/count-alignment`: one rule names the unit it bounds (every reply), the other does not, and two spellings of one limit read as drift. The fix in §3 clears that too.

## §3 The fix is a decision, not a bigger number

The wrong instinct is to nudge a number until the error goes away. The right one is to notice the checker has surfaced a decision you never actually made: which rule governs which reply. There are two honest answers. Reconcile the bounds into one satisfiable band, or scope them so they never apply to the same message. Scoping means scoping both. A guard on the floor alone changes nothing about the cap: a flat rule applies to every reply, the returns explanation included, so the two bounds still meet there. The exception has to be carved out of the default, `UNLESS` the case on one side and `WHEN` the case on the other, so the guards are complementary and no reply falls under both. Scoping keeps both intentions, brevity for routine replies and depth for the returns explanation, without asking a single reply to be two lengths at once.

support.tg ✓ compiles

```typeglish
# Role
You are a support agent for an online electronics retailer.

# Constraints
@@ brevity: a routine reply over three sentences gets skimmed
- UNLESS you explain the return policy THEN MUST keep every reply to at most 3 sentences.
@@ thorough: a returns explanation has to cover the conditions
- WHEN you explain the return policy THEN MUST answer in at least 5 sentences.
```

Now the two bounds have complementary guards: the cap holds `UNLESS` you explain the return policy, the floor holds `WHEN` you do. The guard on the default is not optional. A flat cap still applies inside the exception, which is exactly the collision the first version of this post shipped. No single reply falls under both rules now, so the solver is content.

tg check - output

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

The arithmetic works out. And because both scopes are written into the rules, a future edit that drops either guard puts the conflict straight back, and the checker says so.

## §4 The rest of the arithmetic

Length bounds are the most common case, but the same solver reasons about every quantity you put in a prompt. It is worth knowing what else it can prove, because these are the numbers that break agents quietly:

- **Action counts** (`logic/action-count`) - one action given two different counts, like "call five tools" and "call six tools" for the same step. The agent cannot do both.

- **Set cardinality** (`logic/cardinality`) - two counts for one set that cannot both hold, like "there is only one escalation path" and "there are many escalation paths."

- **Insufficient sets** (`logic/insufficient-set`) - a directive that needs more items than the set actually holds, like "offer three alternatives" when only two are defined.

They share a shape with the length case: each is a claim about a quantity, each is invisible to a reader skimming for tone, and each is decidable the instant you treat the numbers as numbers. That is the whole move. Vague magnitudes ask the model to guess and let it guess differently every time. Precise ones let a solver check your work, and occasionally tell you that the work does not add up, which is the most useful thing a spec can do before it ships.

Field note

The `logic/numeric` proof is Z3-backed and shipped in [TypeGlish 0.1.0](https://typeglish.dev/blog/typeglish-0-1-0). A numeric conflict is the arithmetic cousin of the modal conflicts in [your prompt argues with itself](https://typeglish.dev/blog/prompt-contradictions): same idea, different operator, both proven rather than guessed. And the reason vague magnitudes never get caught is the reason to write measurable rules in the first place, which is the before-and-after in [the rewrite of a bloated support prompt](https://typeglish.dev/blog/rewrite-bloated-support-prompt).

## FAQ Common questions

**Why does my agent ignore the length limit in my prompt?**

The usual cause is a second rule that contradicts the first. If one rule says at most 3 sentences and another says at least 5, no output satisfies both, so the model picks one per reply and the limit looks ignored. A vague limit like "keep it short" has the opposite problem: there is no number to hold it to. Give every length rule a concrete bound and make sure two bounds cannot both fire on the same reply.

**Can I set both a minimum and a maximum length in a system prompt?**

Yes, as long as the minimum is not greater than the maximum and the two apply to the same situation. At least 2 and at most 5 sentences is a satisfiable band. At least 5 and at most 3 is a numeric impossibility, and TypeGlish rejects it at compile time with `logic/numeric`. If you want a short default but a longer answer for one case, guard both: `UNLESS` the case on the default and `WHEN` the case on the exception, so the two never apply to the same reply. A guard on the exception alone leaves the flat default applying inside it.

**How do I stop two rules in my prompt from contradicting each other on length?**

Decide which rule wins instead of shipping both and hoping. Either reconcile the numbers into one satisfiable band, or scope them so they never fire together, for example `UNLESS` you explain the return policy `THEN MUST` keep every reply to at most 3 sentences, and `WHEN` you explain the return policy `THEN MUST` answer in at least 5 sentences. Running `npx typeglish check` proves whether any two numeric rules can both be true; if they cannot, it fails the build with `logic/numeric` and names the two numbers.

**What is the difference between at most and at least in TypeGlish?**

They are inclusive numeric bounds. "At most 3" means 3 or fewer; "at least 5" means 5 or more. The checker reads them as real inequalities and solves them, so it can prove when a set of bounds has no solution (at most 3 and at least 5 cannot both hold) rather than treating the words as decoration. That is why a numeric conflict is a blocking error, not a style warning.

∿ washed up Jul 19, 2026 ∿
