docs← Back to article

Markdown for LLMs

Lifecycle pitfalls

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

Download this articlePlain text ↗
# Lifecycle pitfalls

Wrong forms, silent outcomes, `LDC-E` diagnostics, typical formalizer
mistakes, and how to detect them. "Confirmed by running" items were
reproduced by running the examples.

## 1. Overdue without completeness is `UNDETERMINED`, not `VIOLATED` (confirmed by running)

An achievement breach requires four conditions, the third being
a completeness ground (explicit non-performance, a certificate, a decision). The
"fee unpaid, deadline passed" case without an explicit `not fee_paid` gives:

```text
evaluate positions(); expect position(PayFee, UNDETERMINED);
```

(`examples/achievement-ladder/tests/02-overdue.lawtest`, passes.)
An AI agent writes in a `VIOLATED` expectation "by common sense" — the test
goes red. Detection: read the achievement rule literally; a breach must be earned by completeness,
not by calendar.

## 2. Subject-matter predicates instead of cycle std literals

`obligation_terminated(o)`, `minimum_violated(c)`,
`weekly_rest_violated(e, er)` are world facts: rules read them, the
lifecycle never sees them. Cycle acts are only the unary/binary/ternary
literals `urn:law:std#waived/suspended/terminated` over the position id, with
a source, scope (`full` or `violation`), and time. Without an interval
the literal acts as a point on the decision date. Detection: ask
`positions()` — a subject-matter predicate never changes a status.

## 3. `DEFEATED` as absence (confirmed by running)

A defeated position is present in `positions` with status `DEFEATED`,
carries payload and `createdBy`, proof shows the winning application —
but publishes NO status literal and no links.
A rule reading `fee_paid(p)` as an ordinary fact never sees the defeated
position's conclusion: a conclusion with no surviving candidate has no accepted support.
Detection: `DEFEATED`
reads only via the `positions()`/`normative_status` query, never via
a rule body.

## 4. A breach from an opposite norm

"There is a prohibition — so the act breached the duty" — no:
a breach is not a logical conflict and never arises from an
opposite norm's presence. An accepted counterexample is needed (maintenance)
or completeness (achievement). Two positions in conflict are a priority
question, not a breach.

## 5. `expired` on a duty

The duty ladder in 0.2 never produces the `expired` API value: after
the window — `SATISFIED` / `VIOLATED` / `UNDETERMINED` / `CONFLICTED`
plus the waiver/suspension/termination statuses. A test expecting `position(X, EXPIRED)` on
a duty passes vacuously (a reserved value that
no implementation produces). Detection: `EXPIRED` belongs only to
powers/liberties/immunities.

## 6. The decision axis instead of the law axis

Position statuses ask the moment the result is issued
(`decision_time`, otherwise `legal_time`), not "which law applies".
A case with "law as of June 1, decision on September 1" gets its September status.
`decision_time` is never named by technical default: a backfilled
value never grounds an answer. Calendar questions never read the axes at all
— the date comes from the question itself. Detection: always name both
axes in tests (as the Union Treaty catalogue does).

## 7. Liberty/immunity with no link — `LIFECYCLE_UNLINKED`

`waived`/`suspended`/`terminated` act on duty and power directly; on
liberty/immunity — only through a linked duty/power, otherwise warning
`LIFECYCLE_UNLINKED`; `claim`/`prohibition`/`entitlement`/`discretion` —
through their lowered form. Detection: the warning in `check`.

## 8. Keywords are lowercase

In this directory's code `bearer` is written
only as a lowercase keyword; keep that spelling in new records.