# 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.