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
Section titled “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
Section titled “2. A field in a constant’s label block”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
Section titled “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
Section titled “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
Section titled “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
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.