Skip to content
docs
Arxo ↗

Vocabulary: pitfalls

For LLMs11 sections

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.

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.

Arxo 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 =.

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.

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.

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

Section titled “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)

Section titled “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)

Section titled “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

Section titled “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

Section titled “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

Section titled “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.

Documentation for Arxo. Writings — blog.arxo.io.

Anonymous visit counts on stats.arxo.io, no cookies.