docs← Back to article

Markdown for LLMs

Strict rules: pitfalls

The source Markdown for this article. Copy it into your assistant or download it as a text file.

Download this articlePlain text ↗
# Strict rules: pitfalls

> Updated 3 October 2026: `concept`, `except_when`, `claim`, `definition … sufficient`, and `default` strength have been removed, together with their special deprecation diagnostic. References below to the former behavior and corpus sources are historical. New source uses `relation`, `unless`, `duty`, a strict rule, and `defeasible`.

Wrong forms, silent outcomes, `LDC-E` diagnostics, typical mistakes of
formalizers and AI agents, and how to detect them. Items marked
“confirmed by runs” were reproduced during this research on the installed
engine.

## 1. Head variable bound only by comparison (confirmed by runs)

```law
rule SmallEnterprise strict {
    for e: Enterprise;
    for n: Integer;
    when n <= 100;              // нет позитивного литерала с n
    then small_enterprise(e);
}
```

`LDC-E4101`: every head variable must occur in a positive body
conjunct; comparison, negation, and `not_known` do not bind
variables. Fix: add the literal that binds the variable
(`employee_count(e, n)`), as in the `research.rule_strict.strict_guard`
teaching package. The AI agent often
writes the guard first and forgets the binding literal.

## 2. `unless` on a strict rule

`LDC-E4110`: a strict rule has no exceptions by definition,
exception nodes are not generated. Fix: either the rule becomes
`defeasible`, or the applicability condition is added to the strict body as
a conjunct. The reverse mistake is making a rule `defeasible` “just in
case” when there are no exceptions: then any defeater can remove its
support.

## 3. Defeater against a strictly produced head

`LDC-E4112`: a defeater must have a defeasible producer of the same
head and polarity; a target produced only by strict rules rejects the
attack at `check`. The older lesson about a “powerless defeater
on a strict head” is outdated: such a defeater now fails to compile instead
of silently not working.

## 4. Silent Not established, not refuted: expected refusal, got absence of inference

If no rule fired — the answer is Not established, not refuted, not Refuted.
Three different causes look the same:

- guard not met (250 employees against a threshold of 100);
- no fact at all;
- premise in Contradiction — a bare literal reads as
  established, and a contested fact does not activate the rule.

Detection: the why-not explanation names the unestablished conjunct;
a guard test on Not established, not refuted must state which of the three causes is meant,
otherwise the test fixes ignorance, not behaviour.

## 5. Priority does not resolve a conflict of two strict rules

Two strict rules with opposite heads give a preserved conflict
Contradiction, and `priority` is powerless here — moreover, priority
over a strict rule is rejected with `LDC-E4105`. Confirmed by
runs: the `research.rule_strict.strict_conflict` teaching package answers Contradiction on both facts without any
diagnostics. The AI agent, seeing Contradiction, first declares priority — on
strict heads that is a compiler rejection, not a fix.
Fix: decide which norm is actually special, and make the pair
`defeasible` + `priority` (see the [priority page](/constructs/priority/)), or recognise the
conflict as substantive and keep Contradiction.

## 6. A separate `relation` for a `definition` name (finding, confirmed by runs)

```law
relation minor(p: Person) kind institutional;
definition minor(p: Person) exact { ... }   // LDC-E1201 + LDC-E1338
```

The name is already declared: definitions and relations share one
namespace, and redeclaration is a static rejection `LDC-E1201` (plus
`LDC-E1338` on the doubled StableId). The compiler synthesizes the relation
itself: a lone definition stands without any companion `relation`. Do not
redeclare the definition's synthesized relation; that creates a duplicate
name. If a publishable vocabulary symbol is needed, publish the definition
itself.

## 7. No rule strength; repeated applicability clause

A rule without strength (`rule R { … }`) or a malformed clause is a
rejection `LDC-E0201`: strength is mandatory; choose `strict`,
`defeasible`, or `defeater`.
A repeated `scope`, `effective`, or `defeat` clause in one block is
`LDC-E1329`. Detection: `law engine check` names the
clause; fix — one clause of each kind per block.

## 8. Keyword name as a binder; head block without lowering

`for event: …` is a rejection `LDC-E0203` (`event`, `case`,
`calendar`, `action` are hard keywords; `state`, `period`, `window`,
`holder` are contextual words and may be names). The grammar accepts a
`then { a; b; }` block, but the compiler does not lower it: warning
`LDC-E1302`, zero rules in the compiled output; fix — separate `then` clauses, each
becoming a separate head rule.