Your prompt argues with itself
No one writes a contradictory prompt. Teams write dozens of individually sensible edits, and the contradiction emerges in the gaps between them - resolved at runtime, silently, one conversation at a time.
When a prompt contradicts itself, the model doesn’t crash, warn, or choose consistently. It resolves the conflict fresh each conversation, weighting recency, phrasing strength, and similarity to the current request. From the outside this looks like flakiness. From the inside it’s determinism you didn’t specify - the model is faithfully executing a spec that says two things.
§1The three species
- Modal conflicts - two rules that cannot both hold: never commit to timelines vs. always give an estimated timeline. The purest form, and the easiest to prove mechanically.
- Scope overlaps - rules that collide only on certain inputs: always answer in the user’s language vs. legal disclaimers must be in English. Fine for months, until a French user triggers a disclaimer. These hide because no single reading of the prompt exposes them - only the right input does.
- Persona-policy conflicts - a personality trait fighting a rule: relentlessly helpful vs. refuse requests outside scope. The persona pulls toward compliance-with-the-user; the policy pulls toward compliance-with-you. Guess which one “goes above and beyond” tips.
§2How a winner gets picked
In our replay experiments, three factors dominate which side of a contradiction wins: recency (later text beats earlier, all else equal), specificity (a rule mentioning the current topic beats a general one), and modal strength as phrased (NEVER beats “try to avoid”). None of these is a policy you chose. They’re tiebreakers standing in for the decision you didn’t know you owed.
A contradiction isn’t a bug in the model. It’s a decision you deferred to the model.
§3Proving it instead of vibing it
logic/contradiction modal conflict rule 12: Agent NEVER commits to shipping timelines rule 41: Agent MUST give an estimated timeline proof: both fire on input class @{shipping_question} fix: scope one rule (UNLESS/WHEN) or delete one
You don’t need a compiler to start. A once-a-quarter human pass works: put every MUST/NEVER in a table, and for each pair ask “is there an input where both fire?” It’s tedious exactly the way the machine version isn’t - which is why we made the machine version - but a spreadsheet catches modal conflicts fine. Scope overlaps are the ones that genuinely need the input-class analysis.
§4Keeping the argument settled
Contradictions are a maintenance property, not a writing property - the prompt that ships clean acquires its first conflict three edits later. Two habits keep it settled: every new MUST/NEVER gets checked against the existing rule table before merge (make it a PR checklist line), and every resolved conflict gets a $TEST pinning the winner, so the losing rule can’t sneak back in a future edit. Old arguments love a rematch.
The logic/contradiction prover shipped in TypeGlish 0.1.0: the first release - it refuses to compile any contradiction it can prove, rather than warning and hoping.