# Vocabulary: pitfalls 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. An individual name without declaration `registered_in(c, Astana)` without `const Astana` — `LDC-E1330`: a bare name in term position must resolve to a `const`, an enumeration member, a package symbol, a dependency export, or a binder. Such a name is now a rejection at `check`. Detection: `LDC-E1330` is fixed by declaring, not by renaming the fact: fact and rule must meet on one name. ## 2. A field in a constant’s label block ```law const CAPITAL: Region = entity_ref("urn:...") { code: "KZ"; } ``` The block after a ready value holds labels; record-constructor fields are part of the value, not of the body. The AI agent carries over the “object with fields” habit from general languages — here the object is already complete to the right of `=`. ## 3. Keyword names and arity `const case: …` — `LDC-E0203` (`event`, `case`, `calendar`, `action` are hard keywords). On an entity the rejection is indirect: `entity period;` does not parse, and every use of the type turns red (`LDC-E2101`). A literal’s arity off-declaration (`registered_in(c)` on two parameters) is `LDC-E2103`. Detection: check every use against the declaration — names in Law DSL are not inferred but verified. ## 4. A constant type not matching `const BASE_FEE: Decimal = 10000 KZT` — `LDC-E2111`. Percentage and money type spellings from prose are not resolved by the current compiler (`LDC-E2101`): write `Decimal` for `25 percent` and `Money` for `10000 KZT`. Confirmed by the `research.vocabulary.company_registry` teaching package: `pub const MAX_RATE: Decimal = 25 percent;` — `check OK`. The AI agent, having read prose type names, writes them directly — and gets a rejection: prose describes the intent, the compiler the 0.2 cut. ## 5. A subtype the wrong way round `Company` in a `Branch` slot — `LDC-E2104` (no implicit conversions). One direction only: a subtype fits its supertype, the reverse is a rejection. Confirmed by the `research.vocabulary.subtype_key` teaching package: `registered_in(b, r)` with `b: Branch` compiles because the slot is `Company`, not the reverse. ## 6. Members of different enumerations in one guard `l == first` with `l: RiskLevel` — `LDC-E2122`: such a comparison answers with `TYPE_ERROR`, and it poisons the whole case document, so the spelling is rejected at `check`, not at runtime. Members have no order: `<` over members is `TYPE_ERROR` too. Detection: check every member guard against the guard parameter’s type, not against a “similar-looking name” of a neighbouring enumeration. ## 7. A constant through itself (statics silent) `const A: Decimal = A;` — `check` is silent, runtime rejects with `CYCLIC_CONSTANT` on every case of the package. Detection: only by running `law test`; eye review — look for self-closure in `const … = …` chains. ## 8. Dotted spelling is the same member (former silent trap) `l == RiskLevel.high`, `l == high`, and `pkg::high` are one constant reference. The dotted spelling used to travel into the compiled output as an identifier answered by no node, and the rule silently never fired — no diagnostics, no issue. Closed today; meeting an old package’s rule “that never fires” with a dotted member — check the build version, not the logic. ## 9. Repeated name; key over a foreign parameter A repeated declaration in the package, including in another of its files, is a rejection `LDC-E1201`: a package’s namespace is one. `key(z)` with no `z` parameter in the signature is `LDC-E1304`. Detection: `law engine check` names the repeated name and the foreign parameter; fix — one declaration per name, keys only over signature parameters. ## 10. Out-of-slice form; undeclared predicate `member = "string"` in an enumeration and `import … as` are out-of-slice 0.1 forms: `LDC-E0206`. A literal of a predicate never declared as a `relation` is `LDC-E2102` (neighbour rejections: `LDC-E2101` — unknown type, `LDC-E2103` — foreign arity, `LDC-E2104` — type mismatch, see items 3–6 above). Detection: check the literal against the `relation` declaration — there is nothing to write a rule about until the name is in the vocabulary. ## 11. Import without context; standard-library versions and names A package with an `import` compiles only with a presented import context: without it every import and every qualified reference is rejected, while `check` stays green. An explicit prelude-package `import` at a different exact version is `LDC-E1110`; a reserved standard-library name on `package` is `LDC-E1113`; an unknown prelude package is `LDC-E1114`. A package declaration shadowing a prelude type is a warning, not an error. The header language version is checked against the registry exactly: `"0.2.0"` for `"0.2"` is `LDC-E1401`.