Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Diagnostic codes

The compiler crate oxc-diagnostics holds the authoritative diagnostic catalog (generated.rs), regenerated from the [[diagnostic]] entries in oxc-syntax/grammar.toml. This appendix is generated from the same entries — it cannot drift from the catalog (CI enforces it via cargo xtask check-drift). Where prose elsewhere in the book disagrees with a row here, this table wins.

A code is O[E|W|I]NNNN — an O-prefix (legacy Ontolog/Oxide; carries through pending a v0.3 rename), a severity letter, and a four-digit number.

The catalog has 388 codes (367 OE + 19 OW + 2 OI), of which 350 are live (a real emitter exists) and 38 are reserved for planned later stages.

SeverityMeaning
OEError: blocks elaboration or load
OWWarning: surfaces, does not block
OIInfo: a note; nothing is blocked

The Status column distinguishes a live code (a real emitter exists in the toolchain) from a reserved one (declared up-front for a planned later stage, no emitter yet — audit dc-04). A reserved code never fires today; it is listed so the number is claimed and the planned gate is documented. There are no library-namespaced codes (mlt::, potency::, ufo::) in the catalog: a theory package authors its constraints as its own rules/checks over the neutral substrate, never as reserved compiler codes. The MLT reasoning codes that once sat in 19xx are gone for exactly that reason; the 19xx codes that remain are the cross-level instantiation-body field-coverage gates (§5.2), which are substrate-level, not theory-specific.

Range allocation

The number’s leading digits group codes by subsystem. These are conventions for allocation, not a hard partition; ranges with no codes today are omitted.

RangeSubsystem
00xx–01xxParse / syntax; name resolution and imports
02xxType / elaboration / predicate-atom validation; membership-write gates
05xxStratification
06xxMeta calculus, refinement, comparison handling, trait conformance
07xxModules, attributes, temporal/modal, forget
08xxField-modifier gates, world-assumption temporal index, positional construction
09xxWorld-assumption conservativity and placement
10xxCWA evaluation, field intent
11xxBridges
12xxBuild composition + .oxbin validation (§16)
13xxRuntime contract + rule-evaluation gates (§17)
14xxIndividual lifecycle (retraction cascade) + write-path stability gates
19xxCross-level instantiation bodies
24xxCollection operators

Parse and name resolution (00xx–01xx)

CodeSeverityStatusNameMeaning
OE0001ErrorLiveUnexpectedTokenParser found a token it did not expect at the current position.
OE0002ErrorLiveUnterminatedStringString literal missing its closing ".
OE0003ErrorReservedInvalidNumberLiteralNumeric literal could not be parsed. The INT/REAL literal grammar is §2.5.
OE0004ErrorLiveInvalidEscapeSequenceUnrecognized escape sequence in a string or char literal.
OE0005ErrorLiveUnterminatedBlockCommentBlock comment /* … */ missing its closing delimiter.
OE0006ErrorLiveNonAssociativeChainComparison (== != < <= > >=) and membership (in, not in) operators are non-associative (§6.6): a bare chain like a < b < c is refused at parse. Pre-refusal the parser folded chains left-associatively, so a < b < c became the Bool-vs-Int comparison (a < b) < c — type-mangled, and in a rule body silently never-true (every row dropped under a green check). Write the conjunction explicitly (a < b && b < c); explicit parentheses ((a < b) == c) are accepted as written.
OE0007ErrorLiveQueryClauseNotYetImplementedA query select-body uses a result-shaping clause — group by … having, `order by … asc
OE0008ErrorLiveModifierMisplacedA declaration modifier appears on a form that does not admit it. abstract attaches to metatype declarations (every type the metatype introduces is abstract) and per-type to concept declarations (pub abstract type Vehicle { … }); fixed is metatype-level ONLY (pub fixed metatype kind = { … }; — classification-mutability is a property of the behavior bundle, not of one type). Any other placement — abstract struct, fixed before a concept declaration, a modifier on enum/rel/trait/rule forms, or a repeated modifier — is refused at parse rather than silently dropped: a swallowed modifier would let the program LOOK constrained while the substrate enforces nothing.
OE0009ErrorLiveEnumPipeFormRemovedAn enum declaration uses the `= variant
OE0011ErrorLiveMissingTerminatorA bodyless declaration is missing its terminating ;. A declaration is terminated by exactly one of: its body’s closing } (pub category Animal { … }), its cover’s closing } (pub kind Vehicle { Car, Truck }), or — when it carries neither — a required ; (pub category Top;). This is the same item-termination rule as Rust (struct Foo; needs the ;, struct Foo { … } does not). The terminator used to be optional: with no ; and no body the parser could not tell where the declaration ended, so a following #[…] attribute was silently re-attributed to the prior declaration and mis-expanded, surfacing a wrong, unrelated error far from the cause. Add the ; at the end of the unterminated declaration.
OE0012ErrorLiveCoverPipeFormRemovedA concept declaration uses the `= A
OE0013ErrorLiveRelationEndMutMisplacedA mut relation-end modifier appears where it is not admitted. mut is legal only immediately before a named end of a concrete relation declaration (rel R(mut end: T, …)); it fires here for mut before an anonymous end (rel R(mut T) — there is no end name to attach the modifier to; name the end) or inside a metarel signature (metarel m(mut a: T, …) — mutability is declared per concrete relation end, never on the metarel; move the mut to the concrete relation declarations the metarel classifies).
OE0014ErrorLiveListCardinalityNotYetImplementedA list type carries a cardinality bound ([T; n..m], [T; >= n], [T; n..m, ordered] — the built-in type forms table and the anonymous-field cardinality default document the surface) that does not enforce yet. The bound parsed but was SILENTLY DISCARDED — the type lowered as a plain unbounded [T] list, so a model could LOOK width-constrained while any width committed with no diagnostic. Refused by name at parse until write-path enforcement lands. Use a plain [T] list for now.
OE0101ErrorLiveUnresolvedNameBare identifier did not resolve to any in-scope declaration.
OE0102ErrorLiveReservedModuleNamestd is a reserved top-level module name; the compiler embeds the stdlib at this namespace. User-declared modules named std would shadow stdlib imports and are refused. Rename the module.
OE0103ErrorLiveUnresolvedUseImportA use a::b::C; import does not resolve to any item in scope. Before this gate a broken use was accepted clean and the only error was a misleading downstream OE0605/OE0101 far from the cause; now the use itself is refused, with a did-you-mean suggestion over the names visible in the target namespace (a dependency package’s pub surface declared in [dependencies], a sibling module, an intra-package pkg::/self::/super:: path). A glob use pkg::*; brings in the target’s pub surface and is never a silent no-op; a glob whose prefix is itself unresolved is the same OE0103.
OE0104ErrorReservedGlobImportUnsupportedReserved (no emitter): a glob use path::*; whose shape is not yet supported. The supported glob — re-export-aware import of a module’s pub surface — resolves; this code is held so a future unsupported glob variant refuses feature-named rather than silently importing nothing.
OE0105ErrorLiveDuplicateImportBindingTwo use imports bind the same local name to DIFFERENT definitions — use va::Kind; use vb::Kind; (with or without an as alias on either) — so a bare use of the name resolved silently to whichever import the resolver consulted first, and its meaning flipped with import order. This is refused loudly: a local import name must resolve unambiguously. Fix it by giving the imports distinct as aliases, or by dropping the redundant use. Re-importing the SAME definition under one name is idempotent and allowed; a single import that binds one name across multiple namespaces at once (for example a shared relation and its decorator macro) is likewise not a conflict. When the conflicting imports are metatype, metarel, or metaxis introducers, the ambiguity is reported instead by the introducer/binding diagnostic at the point of use, which names both candidate definitions; name clashes introduced by a glob use m::*; follow separate shadowing rules and are reported at the use site.
OE0106ErrorLiveGlobImportAmbiguityA name brought into scope by two or more glob imports (use m::*;) resolves to DIFFERENT items, and no explicit import or local declaration disambiguates it, so a use of the name is ambiguous. This is refused at the use site: the resolver never silently picks one glob’s item over another’s, and its meaning must not depend on import order. Fix it by importing the intended item explicitly (use m::Name; — an explicit import silently shadows the globs), by qualifying the reference (m::Name), or by dropping one of the conflicting globs. An unused ambiguous name is not reported; two globs that re-export the SAME item are not a conflict; an explicit import or a same-module declaration always shadows a glob import of the same name.
OE0107ErrorLiveNavViewFilterUnboundNameA bare value name in the where filter of a navigation-view field (f: [T] from Rel.endpoint where <predicate>) is not in scope. The filter binds exactly one local name: the endpoint name written after the relation in the from clause — supported in from Supports.supported. Module-scope declarations (concepts, relations, rules, constants) remain visible, so where supported : Dependent, where under13(supported) and where supported.age < 13 all resolve. Neither self nor the relation’s other endpoints, including the holder whose field is being computed, are available in the filter. The message names the local that is available without assuming the unresolved name was a typo. Fix a typo by using that local. If the condition genuinely needs the holder or another endpoint, express it in a pub derive rule and call that rule with the available local. Reported instead of the generic unresolved-name refusal only for an unresolved bare value inside a navigation-view where filter. An unresolved callee, qualified path, or name outside such a filter keeps the generic code.
OE0150ErrorLiveRelationSubsumptionArityMismatchRelation R1 <: R declaration where R1 and R have different parameter counts.
OE0151ErrorLiveRelationSubsumptionEndpointVarianceRelation R1 <: R declaration where an endpoint position’s type in R1 does not specialize (<:) the corresponding position in R.
OE0152ErrorReservedRelationSubsumptionCardinalityViolationRelation R1 <: R declaration where a slot’s cardinality [c..d] does not refine the parent’s [a..b]. Refinement requires c >= a and (d <= b or b = *).
OE0153ErrorLiveRelationSubsumptionMetarelMismatchRelation R1 <: R declaration where meta(R1) != meta(R) (MVP rule — cross-metarel subsumption is deferred).
OE0154ErrorLiveRelationSubsumptionCycleRelation subsumption graph contains a cycle (R1 <: R2 <: ... <: R1) — the substrate requires an acyclic subsumption DAG.
OW0010WarningLiveNonCanonicalClauseOrderA concept declaration writes the : iof-instantiation clause before the <: specialization clause. Both orders parse and mean the same thing — the two clauses are independent (parents are an unordered set on each axis) — so this is a style WARNING, not an error: it never blocks ox check/ox build. The canonical spelling places <: before : (pub subkind Penguin <: FlyingAnimal : Vertebrate_Species { … }), mirroring the order arithmetic — specialization parents sit at the concept’s own order, instantiation parents one above. oxfmt will normalize the order for you once the CST-driven formatter lands; reorder the clauses to silence the warning in the meantime.

Type, elaboration, predicate atoms, membership writes (02xx)

CodeSeverityStatusNameMeaning
OE0201ErrorLiveTypeMismatchExpected one type but found a different one — expected X, found Y.
OE0202ErrorLiveArityMismatchFunction call has the wrong number of arguments.
OE0203ErrorLiveNonExhaustiveMatchmatch arms do not cover every constructor of the scrutinee type.
OE0204ErrorLiveUnknownFieldField access x.f — in a derive/check/bridge rule body or a fn/mutate body — where the receiver’s established type, a struct or concept (pub type ..., or a vocabulary introducer) including inherited fields and any operand : T type-test narrowing in scope (a rule-body type-test or a comprehension where e : T), declares no field named f. In rule bodies, reported only on provable absence: f must be missing from every established concept of the receiver, since an Argon individual may be classified under several concepts (a field on any asserted concept is admitted). Evidence-gated: a base with no established concept (an unbound variable, or a qualified path to a declared type/enum such as Color.red) is skipped.
OE0207ErrorLiveRequiredFieldMissinginsert T { … } omitted a field that T or one of its <: ancestors declares as required at construction (intent Required — not T? / Truth4Of<T> — with neither a default nor a from-navigation source). Emitted by the runtime construct path (oxc-runtime) as a loud refusal with nothing committed, rather than silently minting an incomplete individual. Distinct from OE1014 RequiredFieldUnasserted, the CWA evaluation-time case; the OE0207 number is a known wart pending the v0.3 renumber.
OE0208ErrorLiveAmbiguousFieldFromMultipleParentsA concept inherits SAME-NAMED fields from two <:-incomparable ancestors (a field diamond — §5.2): no unique binding exists for the name, and the substrate offers no automatic merge, override-by-position, or last-wins resolution. Before this gate the collision silently resolved rightmost-parent-wins at every flatten site (ox gen schemas, the nav carrier scan) — swapping the parent order swapped the field’s type, with zero diagnostics. A LINEAR declarer chain is NOT a diamond: a unique most-specific declarer (every other declarer among its ancestors) is the field’s binding, so a subtype redeclaring an inherited field stays admitted. Fix it by renaming one of the colliding fields, or by redeclaring the field on the child to bind it explicitly. The per-parent field qualifier (bar.Parent::field) is the designed future disambiguation surface and does not parse yet. In-file <: graph only (cross-module parents defer, like OE0242/OE0243).
OE0210ErrorReservedIofInsertOnRigidTypeReserved (designed, not yet wired — §7.5): a dynamic insert iof(x, T) reclassifying an individual into a rigid type (rigidity::rigidkind, subkind, category) rather than an anti-rigid one (role, phase, mixin). To create a new individual of a rigid type, use insert T { … }. The rigidity gate is not yet wired into the runtime iof path; this entry reserves the code for it.
OE0211ErrorLiveIofInsertOnDefinedManual membership write into a defined concept whose membership is derived, not asserted: insert iof / delete iof on an iff or shape-defined concept (or one with a defined <:-ancestor), and insert C { … } construction of a shape-defined concept or a subtype beneath one. Update the underlying state instead; the substrate auto-classifies. Emitted by the runtime mutate path (oxc-runtime): IofInsertOnDefined, the upward-closed ancestor case (IofInsertOnDefinedAncestor), and the construct door (ShapeDefinedConstruct).
OE0212ErrorReservedMetaArgUnboundReserved refusal for an unbound argument position of the type-position reflection intrinsics (meta/iof/specializes/extent). implements is EXEMPT by design: $implements is a finite catalog-closed relation, so both of its positions may be free — enumeration (free t: the implementing types; free tr: a type’s traits) is the intended use. The current engine answers the other intrinsics’ free positions relationally too, by enumerating their materialized $-relations, so this code has no emission site today; it is reserved for argument shapes a future evaluator cannot satisfy relationally.
OE0213ErrorLiveIofInsertIntoBotinsert iof(x, Bot) (or delete iof(x, Bot)) targets Bot/, the empty concept (lattice bottom), which by definition has no instances — the assertion is a contradiction and is refused at ox check / ox build. A sound empty-category refusal that follows from Bot’s definition alone, NOT from concept-vs-concept disjointness (which stays reserved, OE1904). The dual Top/ is the lattice join — every individual is an instance of it — so a rule body Top(x) ranges over the whole domain.
OE0214ErrorLiveCoverClauseUnsupportedA concept declaration carries a cover body (pub category Pet { Dog, Cat }) — the surface parses, but the elaborator does not yet thread cover members into the subkind hierarchy, so the body would assert NOTHING: no classification of the members under the declared type, no partition/exhaustiveness axiom, zero diagnostics. It reads exactly like it should mean something, so silently accepting it flattened whole taxonomies. The threading of cover members into the subkind hierarchy is designed but not built; until it lands, state the intent explicitly: declare each member a subtype (pub type Dog <: Pet;) and, for the cover/exhaustiveness semantics, add a complete/partition group axiom over the parent (partition Pet { Dog, Cat } — OE0242/OE0243 validate it).
OE0220ErrorLiveFactReferencesUnknownPredicatepub fact P(...) references a predicate name that does not resolve to a concept or relation in the module’s fact-head scope (same-file declarations, plus imported concepts/relations the file’s use/prelude scope reaches). When the name IS declared elsewhere in the workspace but is out of this scope, the message says so and names the working pattern: mint the individual where the concept is declared (pub fact P(x); in the declaring module) and reference it cross-module by its bare name — individual identity is the global bare-name hash — or bring the concept into scope with a module-qualified use.
OE0221ErrorLiveFactArgArityMismatchpub fact P(args) argument count doesn’t match the declared arity of P (1 for concepts; the relation’s parameter count for relations).
OE0222ErrorLiveFactArgTypeMismatchpub fact P(args) argument shape doesn’t match a declared parameter type (e.g., a literal in a slot that expects an individual).
OE0223ErrorLiveRuleReferencesUnknownPredicateA rule body or head (derive / check / bridge) references a predicate atom P(...) whose head name does not resolve to a declared concept, relation, derive/query/check head, or reflection intrinsic in scope (§7.3.1). Predicate vocabulary must be declared; OWA governs the truth value of instances of a declared predicate, not whether the predicate name itself exists.
OE0224ErrorLivePositionalConceptInsertA positional insert C(...) in a mutate body where C resolves to a concept constructs nothing — parenthesized insert asserts a relation tuple, and the head is a concept, not a relation. Use the brace form insert C { field = value, ... } to construct an individual. Construction is brace-only; parens are reserved for relation-tuple assertions.
OE0225ErrorLiveRuleAtomArgArityMismatchA predicate atom P(args) in a derive / check / bridge rule body or head supplies the wrong number of arguments for the declared arity of P (1 for a concept-as-predicate; the relation’s parameter count for a relation; the head arity for a derived predicate). The non-ground analogue of OE0221 (pub fact), split by context per the OE0220→OE0223 precedent.
OE0226ErrorLiveRuleAtomArgTypeMismatchAn argument to a predicate atom P(args) in a derive / check / bridge rule body or head has a type incompatible with P’s declared parameter type at that position (e.g., a logic variable bound elsewhere to String used in a slot declared Int, or a literal of the wrong primordial). Reported only when both the argument’s type and the parameter type are concretely known. The non-ground analogue of OE0222 (pub fact).
OE0227ErrorLiveRuleValuePathUnresolvedA multi-segment path (a::b) in a rule body resolves to nothing under the unified value-position resolution order (bound rule variable, enum constant, axis value, type reference, declared individual — and, in predicate position, rule heads / concept extents / relations first). Before this gate the lowering silently turned an unresolved path into a VARIABLE named by the joined path — rigidity::anti_rigid then tripped OE1303 as an “unbound variable”, and a path in predicate-argument position bound everything and over-derived. Refused at ox check / ox build instead, naming the path and the namespaces searched. Also fires when a bare A::B rule atom resolves to a CONSTANT (a constant is a value, not a predicate; the path :: Ident metaEq sugar applies only when the left side is a bound term AND constant resolution declines the path), and when a qualified path matches several declarations (qualify further). Fix the spelling, declare the missing symbol, or qualify the reference.
OE0228ErrorLiveRuleValueNameAmbiguousA bare identifier in a rule-body value position is BOTH a rule variable (a head parameter, or a comprehension/quantifier/aggregate binder) AND resolves to a declared constant (a declared individual). Refused naming both candidates rather than silently picking one — the lesson of Rust’s bindings_with_variant_name lint, promoted to a refusal: silently reading it as a variable shadows the constant (the pre-S0 behavior that made knows(x, carol) over-derive); silently reading it as the constant changes the rule’s arity semantics. Rename the variable, or qualify the constant (module::name). A bare identifier that occurs ONLY in body positions and resolves to a declared constant IS that constant — no ambiguity, no error.
OE0229ErrorLiveUnknownFieldWriteA mutate-body write names a field the target concept does not declare: a constructor field (insert C { f: v }), an update … set { f = v } assignment, or an insert … into x.f target, where f is missing from C and from every ancestor in its <: chain. Reported only on provable absence — the concept and its full ancestor chain must be declared in the elaborating file; cross-module targets defer to runtime. Without the gate a typo’d field name persists under a property id no read path resolves — silent data loss.
OE0230ErrorLiveInsertIntoNonCollectioninsert <elem> into x.f targets a field whose declared type is not a collection ([T] / List<T> / Set<T>). insert into appends to collection fields; on a scalar field it would silently replace the committed scalar with a one-element list, corrupting the field’s type and detaching every refinement and derive that reads it. Use update … set { f = … } for scalar writes.
OE0231ErrorLivePropertyIdCollisionTwo distinct Type::field pairs fold to the same property NameRef under the hash-derived property_id_for_field stand-in. Property ids are masked into the INT4 wire band [1, 2^31-1] (the high bit is reserved); the 31-bit space leaves room for collisions at workspace scale (birthday bound ≈ 2^15.5 field identities), and a collision is silent data aliasing — the two fields would share one storage column, the later declaration’s reverse-lookup entry shadowing the earlier. Refused at module load: the closed-set ConceptDecl walk that builds the resolution map is the injectivity oracle, so the collision converts to a build/load refusal naming both pairs instead of corrupting writes. Rename one field, or rebuild once the sequential interning table retires the hash stand-in entirely.
OE0232ErrorLiveRelationEndpointMissingA write places an individual into a typed slot — a relation endpoint or a concept-typed field — that no committed event introduces: a dangling reference. The ruling: such writes REFUSE missing individuals at write time; an individual EXISTS iff some committed event names it (an iof assertion OR a property assertion — full classification is not required, preserving §3.5 domain-conservative ghost-individual semantics). Fires on three surfaces. STATIC: a pub fact R(…, e, …) whose identifier endpoint e is in no concept-membership pub fact C(e) in the elaborating file (build-time, all information in source; cross-module endpoints defer to runtime). RUNTIME (relation): an insert R(…) in a mutate body (or CLI/serve write) whose individual endpoint resolves to an id no iof/property assertion in the store names. RUNTIME (field): an insert C { f: o } / update t set { f = o } whose concept-typed field f is given an individual o that no committed event names — the field-side counterpart of the relation endpoint floor, since a concept-typed field is a typed slot exactly as an endpoint is. Both runtime surfaces are checked against the overlay’s read-your-writes view, so an individual constructed or classified earlier in the SAME body counts. Without the gate, a relation’s declared signature (or a field’s declared type) is decorative: derives joining serve rows whose endpoints are in no extent, and a forged below-floor #i reference would slip past the serve floor-bound. Atomic — raised before the tuple/field is buffered, so the whole body commits nothing. Existence is the FIRST gate; TYPING is the layer above it (OE0258): once the individual exists, a closed-world target concept refuses a write over an UNclassified individual (CWA cannot silently expand a closed extent), while an open-world concept admits it. delete iof-driven cascade is a recorded non-decision (deferred). Construct or classify the individual first, or fix the reference.
OE0233ErrorLiveAbstractTypeConstructThe program asserts a direct instance of an abstract type: insert T { … } where T is declared abstract (or is introduced by an abstract metatype), a direct insert iof(x, T) classifying an existing individual under it, or a positive pub fact T(x) seeding one at elaboration. abstract means NO DIRECT INSTANCES — abstract types structure the hierarchy (and are exempt from trait impl-coverage obligations, OE1327) precisely because every individual is classified through some non-abstract subtype. Assert or classify under a non-abstract subtype instead; subtypes are unaffected, and pub not_fact T(x) (refuting membership) stays legal. Emitted at ox check/ox build where the target is statically known; the runtime enforces the same refusal at the write path (atomically — the whole mutation rejects) for targets only resolvable at execution, and at artifact load for hand-built IofAssertion events that would bypass the elaborator.
OE0234ErrorLiveFixedReclassificationA mutate body re-classifies under a type introduced by a fixed metatype: insert iof(x, T) or delete iof(x, T) where T’s introducing metatype is declared fixed. fixed means classification is DECIDED AT CONSTRUCTION — membership of fixed-introduced types never changes over an individual’s lifetime, which is what makes static check discharge over them sound (§10.2: rigid designation = fixed classification). Construction (insert T { … }) is NOT re-classification and is unaffected; types introduced by non-fixed metatypes classify and de-classify freely (dynamic is the default — the restriction is the opt-in, the same posture as check). Emitted at ox check/ox build where the target is statically known; the runtime write path enforces the same refusal (atomically) otherwise. Importing a vocabulary can never change mutation semantics by axis NAME — only the declared fixed modifier carries this behavior.
OE0235ErrorLiveGenericTypeApplicationUnsupportedA generic type application carries arguments the elaborator does not interpret. User-declared concept generics are decorative: a concept’s <T> parameters parse but reach no storage slot (ConceptDeclBody has no type-parameter column), so an application like Boxy<Int> / Boxy<Int, String, Bool> / a bare Boxy (arity 0 against a 1-param concept) / NotGeneric<Int> (arguments on a non-generic concept) was accepted with the arity and applicability silently discarded — the §6.2 ‘generic applications subtype only by equality’ rule and the §6.1 bounded-generic grammar both imply the arguments are semantically real. The library generics with a real construction surface are unaffected (List<T>, Set<T>, Option<T>, Result<T, E>, Range<T>, Truth4Of<T>, and the live reflective TypeRef<C>); their argument shapes ARE interpreted. Refused at ox check / ox build at the use site until parameterised user concepts are real (the type-parameter plane is V1 bounded-generics territory). Drop the arguments, or use one of the supported library generics.
OE0236ErrorLiveMutateFieldValueTypeMismatchA value position in a mutate body is assigned to a declared field whose type it does not match: an update target set { f = v } whose v is a value of a primordial incompatible with f’s declared type (a String into an Int field, an Int into a Date field, a structured CBOR record into a scalar field). Pre-refusal these assignments bypassed any runtime re-check (the write path’s coerce_value_for_declared_type was temporal-coercion-only, falling through other => Ok(other) for the mismatch), so the wrong-typed value committed and downstream rules derived silently-wrong rows (an Int in a Date field made d < <date> unconditionally true under the cross-type comparison fallback — see OE0630). Emitted at ox check / ox build for the statically-decidable, sound subset — a primitive literal whose primordial type UNCONDITIONALLY contradicts the field’s declared primordial type (the constructor insert C { f: lit } and update target: T set { f = lit } paths), refused before a doomed artifact is built rather than late at query/serve. The static gate is a STRICT SUBSET of the runtime gate: value-dependent pairs the runtime may coerce (a String literal into a parse-coercible temporal / exact-numeric field, an Int into the numeric tower or Duration day-count, an integral Real into Int/Nat) stay deferred to the runtime mutate value path, which remains the backstop for those and for cross-module field-type chains. The Value::Cbor carrier seam is bounded by tag inspection: a tag-30 exact rational is checked against the numeric tower (accepted into Real/Decimal/Money/Int, refused into Date/Duration/String/Bool), and a structured map/array/enum-payload carrier is refused into the NATIVE primordials that never ride a structured carrier (Int/Nat/Real/Date/Duration/String/Bool) — a Money struct into Int is the canonical refusal. Money and Decimal are EXEMPT: today they are represented AS opaque/structured CBOR carriers, so a structured value is their legitimate form; an indecodable opaque blob or a concept-typed field also passes through. The field-coercion path (TextDate/Duration/Real parse, IntDuration day-count) stays accepted where the surface defines it.
OE0237ErrorLiveFieldDefaultUnsupportedA field declaration carries a default-value clause field: T = expr. Book §5.1 specifies full default semantics (lazy evaluation at access, self resolution, resolution order), but the elaborator never reads the expression — the parser consumed it as token soup and the lowering hardcoded default: None, so the default silently never applied: a required field with a dropped default still refused construction (OE0207), and an optional field T? = expr constructed successfully with the default absent (silently wrong extents downstream). Refused at parse until the lazy-default evaluator lands rather than accepting a clause the substrate ignores. Drop the = expr and supply the value at construction, or use a from-navigation source (field: T from Rel.endpoint) for a derived value. The from-clause form is unaffected — it is parsed and elaborated.
OE0238ErrorLiveUpdateOnUnclassifiedupdate … set { … } targeted an individual that is an instance of no concept at all — its classification set is empty. A primitive (where) concept’s necessary invariant is keyed on a classifier, so an unclassified target evaluates none of them: the field write proceeds wholly unchecked and the corrupt value silently resurfaces (bypassing the invariant) if the individual is later classified into a concept the value violates. Refused loudly by the runtime mutate path (oxc-runtime) rather than written — classify the individual first (insert iof(x, T) or construct it with insert T { … }), then update. Atomic: nothing flushed. Scoped fix; re-validating all properties at classification time is a separate follow-up.
OE0239ErrorLiveFactReferencesDerivedPredicatepub fact P(...) names P, a predicate defined by a pub derive / pub query rule (an intensional / IDB head), not a base predicate. pub fact asserts into an EXTENSIONAL relation (a concept-as-classification or a pub rel); a derived predicate’s extent is COMPUTED by rule derivation, and a pub fact seed would key a different relation node than the rule head reads, so it silently DROPS OUT of the fixpoint (no error, wrong answer). Refused at ox check / ox build rather than emitting an artifact that mis-derives. To give a derived predicate ground tuples that participate in its derivation, use one of the two sanctioned forms: (1) a bodiless pub derive P(args); clause — a derive head with no :- ... body over CONCRETE arguments is itself a ground fact that unions with P’s other derive clauses and rules over the same head; or (2) declare a base relation the rule reads — pub rel Base(...), seed it pub fact Base(...), and add a pub derive P(...) :- Base(...) clause. Either keeps P a single-origin intensional head; pick the bodiless-derive form to seed P directly, the base-rel form when the seed tuples are themselves a reusable extensional predicate.
OE0240ErrorLiveGroupAxiomDisjointOverlapA disjoint { A, B, … } group axiom declares its members pairwise non-overlapping, but a write would classify one individual into two of them at once — membership evaluated in the fixpoint (concept atoms Ai(x) and Aj(x)), so asserted and derived membership count alike, including shape-defined members whose extent is never asserted. The membership is refused at the write rather than admitted, since an individual in two declared-disjoint siblings makes the partition contradictory and every downstream query over either sibling silently wrong. Carried by a compiler-synthesized check (one per unordered member pair) whose runtime delta-guard refuses the offending insert. Instance-level under the closed-world default (§6.9). #[world(open)] is a live concept attribute, but this disjoint delta-guard evaluates closed-world regardless of the concept’s world — the open-world tolerate softening is designed and not yet wired (the runtime guard does not read the per-concept world map). Retract the conflicting membership, or remove the member from the disjoint set if the overlap is intended.
OE0241ErrorLiveGroupAxiomUncoveredA complete Parent { A, B, … } (or partition) group axiom declares its members jointly exhaustive over Parent, but a write would create a Parent instance that is a member of none of them (Parent(x) with not Ai(x) for every cover member — membership evaluated in the fixpoint, so asserted and derived coverage count alike, including shape-defined members and parents whose extents are never asserted). Under the closed-world default (§6.9) the negation-as-failure covering guard fires when no child membership is derivable, and the write is refused rather than admitting an uncovered Parent instance the cover claims cannot exist. Carried by a compiler-synthesized check whose runtime delta-guard refuses the offending insert. #[world(open)] is a live concept attribute, but this covering delta-guard evaluates closed-world regardless of the concept’s world — the open-world tolerate (permit-as-unknown) softening is designed and not yet wired (the runtime guard does not read the per-concept world map). Classify the instance into one of the cover members, or widen the cover.
OE0242ErrorLiveGroupAxiomUncoveredSubtypeA complete Parent { A, B, … } (or partition) group axiom declares its members jointly exhaustive over Parent, but the schema declares a NON-abstract concept S <: Parent (transitively) that is PROVABLY uncovered — provably disjoint from EVERY cover member, so no individual can be both an S and a member (e.g. a disjoint/partition declaration separates S from each member, or the cover is empty). Any instance of S is then a Parent instance in no cover member, so the cover is statically incomplete. A subtype that is merely not a static <:-subtype of a member is NOT refused here: under multiple classification its instances can still be classified into a member at write time, so its covering is deferred to the runtime OE0241 guard (the same deferral applied to a subtype declared in another module). Refused at build by a direct elaboration pass over the <: graph (not a reasoner check — instantiable has no catalog atom to range over). An ABSTRACT subtype is exempt: it has no direct instances, so it cannot witness an uncovered instance. Cover the class (add S or one of its supertypes to the cover, or interpose a cover member S <: Ai), mark S abstract, or drop the disjointness that forces S outside every member.
OE0243ErrorLiveGroupAxiomNonSubtypeChildA complete Parent { …, S, … } (or partition) group axiom names a cover member S that is not a subtype (<:, transitively) of the declared Parent. A cover’s members partition the parent’s extent, so a non-subtype member could classify individuals outside Parent — the covering / disjointness guards would then range over the wrong extent. Refused at supertype resolution. disjoint { … } has no parent and imposes no such constraint. Declare S <: Parent, or remove S from the cover.
OE0244ErrorLiveFromClauseUnknownRelationA navigation-view projection field (field: T from Rel.endpoint) names a relation Rel that does not resolve to a declared pub rel in scope. The from clause projects the field’s value from one endpoint of that relation, so a relation that is not in scope leaves the field projecting nothing — and the clause was previously never checked: only the runtime read from_relation, so a bogus relation built clean and silently projected an empty view. The relation path is now resolved at ox check (the same name-resolution gate concept/relation references pass), and an unresolved or non-relation head is refused. Declare the relation, import it (use), or correct the path.
OE0245ErrorLiveFromClauseUnknownEndpointA navigation-view projection field (field: T from Rel.endpoint) names an endpoint accessor endpoint that is not one of the relation Rel’s declared endpoint names (nor the positional domain/range aliases for the first/last endpoint of a binary relation). The endpoint selects which relation position the field projects; an accessor that matches no position projects nothing — and was previously unchecked (only the runtime read it, so a bogus endpoint built clean and silently projected an empty view). The accessor is now validated against the relation’s declared positions at ox check. Use one of Rel’s declared endpoint names, or domain/range.
OE0246ErrorLiveFromClauseEndpointTypeMismatchA navigation-view projection field (field: T from Rel.endpoint) declares a field type T whose concept is <:-incomparable with the type E of the relation endpoint it projects — neither is a subtype of the other. A navigation view is type-directed: it projects the endpoint and keeps the members that are iof T, so the view is sound for any <:-comparable (T, E) pair (identity when T == E, a no-op widening when E <: T, a real iof T filter when T <: E). But when T and E are unrelated, no endpoint value can be iof T: the view is statically empty and the declaration is type-incoherent. (The narrowing case T <: E — e.g. circles: [Circle] from Contains.shape over a Shape endpoint — is now ACCEPTED and filters to the T-typed members; it no longer errors here.) Widen the field type to a supertype of E, or project an endpoint whose type is <:-comparable with T.
OE0247ErrorLiveFromClauseFilterContradictionA navigation-view projection field (field: T from Rel.endpoint where <predicate>) carries an explicit where type-test endpoint : C whose concept C is <:-incomparable with the field’s element type T. The type-directed view already keeps only the iof T members; a where endpoint : C restates or narrows that selection and must be CONSISTENT with it. When C and T are unrelated, the conjunction iof T && iof C is unsatisfiable: the view is statically empty. A consistent restatement names T itself (where shape : Circle on a [Circle] field) or a <:-related concept; a value predicate (where shape.radius > 0) imposes no such constraint. Drop the contradictory type-test, or align it with the field type.
OE0248ErrorLiveFieldValueNotIndividualA write to a concept-typed field supplies a primitive value where an individual is required: a constructor field (insert C { f: <literal> }) or an update … set { f = <literal> } assignment whose declared field type f: D is a declared CONCEPT, given a primitive literal (a string / integer / decimal / boolean). The value-vs-individual mismatch is the one HARD-CATEGORY refusal sound under Argon’s open-world, multiply-classified semantics (the same arm as OE0222 for pub fact relation endpoints): a value is never an individual of any concept, so it can never inhabit a concept-typed slot — storing it would key a property the read path resolves to a non-individual, silently violating the declared shape. The symmetric arm (an individual written to a primitive-typed field) is also refused. This is NOT a concept-vs-concept disjointness check: an individual of any concept supplied to a concept-typed field is ACCEPTED (it may be reclassifiable; two concepts are never provably disjoint without a declared partition). Supply an individual reference (a constructed binding, a parameter, or a declared individual) for the concept-typed field, or give the field a primitive type if a value was intended.
OE0249ErrorLiveStructFieldMissingA struct VALUE literal T { … } omits a field that T declares: a struct is pure data with structural equality (§5.1), so a literal states every field — there is no construction-time default (field: U = expr defaults are a separate, refused surface). The omitted field’s name and declared type are named. Add the missing field: value, or, when constructing from an existing value of the same struct, use functional update T { ..base, field: value } so the base supplies the rest.
OE0250ErrorLiveStructFieldExtraA struct VALUE literal T { … } supplies a field that T does not declare. A struct is closed data (§5.1): only declared fields may be initialized, and an unknown field is a typo or a stale field name rather than an extension point. Remove the field, or correct it to one of T’s declared field names.
OE0251ErrorLiveStructFieldTypeMismatchA struct VALUE literal T { field: value } initializes a field with a value whose type does not match the field’s declared type. A struct is pure data with structural equality (§5.1); storing a mistyped field would make two values compare unequal-by-type or derive a silently-wrong projection, so the mismatch is refused at build time, naming the field, its declared type, and the supplied type. Supply a value of the declared field type.
OE0252ErrorLiveInsertOfStructinsert T { … } names a struct, but insert constructs a concept INDIVIDUAL — it mints an identity and records an iof classification. A struct is pure data with no metatype and no identity (§5.1): it is constructed as a plain VALUE T { … } (e.g. a let binding, a field value, an argument), never inserted. Drop the insert keyword to construct the struct value, or name a concept type if an individual was intended.
OE0253ErrorLiveMutOnStructFieldA struct field is declared mut. A struct is an IMMUTABLE pure value (§5.1): its fields are fixed at construction and updated only by functional update T { ..base, field: new }, which yields a NEW value rather than mutating in place. The mut modifier marks a concept field updatable by an update … set { … } statement — a notion that applies to identity-bearing concept individuals, not to struct values. Remove mut from the struct field.
OE0254ErrorLiveStructFieldAccessUnknownField access v.f where v is a struct VALUE whose declared struct type has no field f (§5.1). A struct projects field-wise off its declared fields; an absent field is a typo or a stale name. Use one of the struct’s declared field names.
OE0255ErrorLiveStructValueIntoNonStructFieldA struct VALUE is supplied where a field of a different type is declared: a struct value S { … } written to a field whose declared type is a primitive, a concept, or a different struct/enum type. A struct value has structural equality and no identity (§5.1), so it inhabits only a field declared with its own struct type — storing it into an incompatible field would key a value the read path cannot interpret. Supply a value of the declared field type, or change the field’s type to the struct type if the struct value was intended.
OE0256ErrorLiveEnumPayloadArityAn enum payload-variant construction Variant(args) supplies a number of arguments other than one. A payload variant carries a single value (§5.1) — the tag-1011 value carrier holds one payload slot — so Some(7) is well-formed while Some() (zero) and Some(1, 2) (two) are not; the surplus or missing argument is refused rather than silently dropped or truncated. Supply exactly one payload value, or construct a payloadless variant (None) with no parentheses.
OE0257ErrorLiveEnumPayloadPatternA payload-binding match arm Variant(binder) does not bind exactly one fresh variable: a zero-binder Variant(), a multi-binder Variant(a, b), a nested non-binding sub-pattern, or the record form Variant { … }. A payload variant carries one value (§5.1), so its destructuring binds exactly one fresh variable positionally — write Variant(x) => …. Rewrite the arm with a single binder, or match the variant without binding by hoisting the test.
OE0258ErrorLiveRelationEndpointTypeClosedA write places an individual into a typed slot — a relation endpoint (insert R(…)) or a concept-typed field (insert C { f: o } / update t set { f = o }) — that EXISTS (OE0232 passed) but is classified under NOTHING — a bare/ghost individual known only by a property assertion — while the slot’s declared concept T is governed by the CLOSED-world assumption (§6.9). Under CWA concept membership is closed (absence of evidence is evidence of absence), so admitting the write would silently mint the first membership claim about the individual and expand T’s closed extent — refused, the typing layer above OE0232’s existence-only gate. The world assumption DECIDES this arm and nothing else: an OPEN-world T admits the same write (membership assumed-as-unknown), with no diagnostic. Membership is the individual’s full classification (asserted iof UNION derived iff, <:-closed — the decision query_extent/$meta/dispatch share), read against the overlay’s read-your-writes view, so classifying the individual earlier in the SAME body satisfies the gate. Only genuine CONCEPT slots are checked — a primordial position (rel R(a: String, …)) or a primitive field has no extent and is skipped (a primitive into a concept field is the distinct OE0248 value-vs-individual refusal). The Reserved boundary (OE1904) demarcates this gate precisely: when the individual IS classified, but under a concept disjoint from T only by intent (the reversed case — o is iof Pet, the slot wants Person), the write is ACCEPTED, because two concepts are never provably disjoint without a declared partition. Atomic — raised before the write is buffered, so the whole body commits nothing. Classify the individual under {concept} first (this same mutate body counts), or declare {concept} open-world if its membership should be assumable from a write.
OE0259ErrorLiveRuleComparisonOperandMismatchA comparison lhs cmp rhs (==, !=, <, <=, >, >=) in a derive / check / bridge rule body relates two operands of provably disjoint sorts — a hard-category primordial mismatch such as String against Int, or Bool against a number. No value inhabits both sorts, so the comparison can only ever be false (equality) or is undefined (ordering); before this gate it passed ox check and was caught — if at all — only at the runtime comparison operator. The static analogue of the expression-level OE0201 comparison check, carrying the rule-body logic-variable binding context (head-parameter annotation, predicate-argument slot, operand : T narrowing). Reported only on PROVABLE disjointness: two concepts are never flagged (an individual may classify under both), the numeric tower (Int/Real/Decimal/Money) shares one category and is never flagged, and Unknown / unbound operands carry no certainty. Temporal-vs-mismatch is handled on its own stricter path. Fix the operand types or the comparison.
OE0260ErrorLiveInsertSpreadSourceNotStructThe spread base of an insert T { ..v, … } did not evaluate to a struct value. The spread form seeds the construction’s field initializers from the base struct’s fields by exact field name (explicit field: value initializers override them), so the base must be a value of a declared struct — a let-bound struct, a struct-returning fn call, or a struct-typed parameter. An individual, a scalar, an enum value, or an unresolved value carries no field map to seed from. Bind a struct value and spread that, or spell the field initializers explicitly.
OE0261ErrorLiveInsertSpreadFieldUndeclaredA field of the spread base in insert T { ..v, … } is not declared on the target concept or any <: ancestor. Spread matching is by exact field name: every source-struct field must land on a declared field of the target, and a field with no match refuses rather than being silently ignored (data the source value carries must never vanish on insert). Remove the field from the source struct type, rename it to the declared target field it should feed, or construct with explicit field: value initializers instead of the spread.
OE0262ErrorLiveRuleBinderTierCollisionA bare identifier stands as the argument of a user concept / relation / rule — a VARIABLE-expecting predicate slot — but resolves to a declared type / relation tier (a type-as-value). This is the POSITION analogue of OE0228 (a bare name that is both a binder and a declared individual): in a variable-expecting slot a bare declared-name is genuinely ambiguous — is it a body-local join variable that should enumerate the predicate’s partners, or the declaration used as a type-as-value constant? The value-position type-as-value coercion runs before the full binder set is known and, with only the head parameters excluded, silently PINNED the argument to the declaration’s TypeRef (lowering it as a constant handle rather than a join variable). That is the same silent-flip class OE0228 refuses, in the tier direction: a lowercase relation name (whose naming convention overlaps variable convention) used as a join variable was pinned to the relation with no diagnostic, so the rule joined against a constant where it meant to bind. Refused rather than pinned. The type-EXPECTING positions keep coercing and are never flagged: the reflective heads rel(r, m) / arm(r, pos, t) / iof(c, T) / specializes(T1, T2), a meta(x) == T / comparison / ascription type operand, and a fn argument (a type passed to a pure function). A QUALIFIED name (module::name) is unambiguous and coerces to the type-as-value in any position. Fix: rename the variable so it does not collide with a declared type or relation, or qualify the name to use it as a type-as-value constant.
OE0263ErrorLiveStructLitMultipleSpreadsA struct literal or insert T { … } field-init list carries more than one ..base spread. One spread seeds the field map and the named initializers override it; a second spread has no defined merge order and was previously dropped silently (first spread wins, the rest vanished). Combine the sources into one struct value first (let merged = S { ..a, field: b.field };), then spread the merged value.
OE0264ErrorLiveStructLitConceptHeadThe head T of a struct VALUE literal T { field: value, … } resolves to a declared concept, relation, trait, or other non-struct declaration. A brace literal constructs pure DATA — a value of a declared struct, with structural equality and no identity (§5.1) — so its head must name a struct. A concept declares identity-bearing INDIVIDUALS, and an individual is created only by insert T { … } inside a mutate (or test) body, which mints the identity and records the iof classification; this is the same struct/concept boundary OE0252 enforces in the other direction (insert refuses a struct head). Previously the literal passed ox check and died at first evaluation with a generic uncoded runtime error. Declare T as a struct if a plain value was intended, or construct the individual with insert T { … } in a mutate body. An enum-headed brace literal is not this refusal: enum values construct through their variant paths.
OE0265ErrorLiveFnBodyInsertA fn body contains an insert … expression. A fn is the pure plane of the rule ladder: it lowers to pure compute, is cacheable on its arguments, and is callable from any mode — including rule bodies evaluated inside the reasoner’s fixpoint — so it must produce a value with no side effect. insert constructs an individual in the store (an identity-minting write) and belongs to the transactional planes: a mutate body, or a test body (which executes mutate-shaped statements against the test’s scratch store). Before this gate the form passed ox check and then misbehaved by position: a bare or block-tail insert died at first call with a generic uncoded error, and an insert bound by an unused let was dropped silently — the write the author spelled never happened. Move the construction into a mutate (or test) body and pass the constructed value to the fn as an argument, or construct a struct VALUE T { … } if pure data was intended.
OE0266ErrorLiveMutateInsertUndeclaredRelationA trait-impl mutate member’s insert P(...) / delete P(...) tuple write names a relation P that no declaration anywhere in the program defines. The runtime resolves a tuple-write target against the whole-program artifact — every package’s relation declarations, matched by qualified path or bare-name suffix, imports and package boundaries ignored — so a target no package declares can never succeed: it aborts the mutation at the rule’s first firing (“relation not declared in module”), latent until data first makes the rule applicable. Declare the relation (pub rel P(...)) in the package that owns it, or correct the target name. Unlike the scoped module-level mutate gate (OE0223), this gate mirrors the runtime resolver program-globally, so a relation declared in any package resolves and is not refused here.
OE0267ErrorLiveImmutableRelationEndNonIndividualContextRelation ends are immutable unless marked mut. An immutable end is a promise: each fact’s bond at this end is permanent — no write can rewrite or delete it; it dissolves only when an individual at one of the relation’s OTHER ends is deleted (the deletion cascades and removes the fact). That promise is fulfillable only when every other end holds identity-bearing individuals — things with a create/delete lifetime. Here it is not: either another end is typed by a value that is never created or deleted — a primordial (Int, String, …), a struct/enum value, or a type/trait reference (TypeRef / Metatype / TraitRef) — or the relation is unary and has no other end at all. Had the declaration been accepted, every fact would be frozen forever — impossible to update or retract — and the individuals it mentions would become undeletable, since deleting an individual requires releasing every fact that mentions it and this end’s release condition can never fire. Marking the VALUE end mut instead does not help, and that declaration is refused by this same check: the value end’s mut would only let NEW values accumulate beside the old ones (an insert adds a fact; removing one requires every end mut), while the flagged end’s permanent bond still holds every fact in place — each value ever recorded would stand forever, and the individual would still be undeletable. Fix: write mut before the flagged end’s name (e.g. pub rel hasAge(mut p: Person, n: Int)), then choose the reading you mean: with mut p alone the value is constitutive — a person’s n is fixed at its first assertion and the fact exits only when the person is deleted; if the value should change over time, mark BOTH ends mut (updating is delete + insert, and a matched delete requires every end mut, OE1402). mut changes only the facts’ lifecycle, never the individuals’: retracting a fact never deletes the individuals it mentions. Keep an end immutable exactly when the honest exit of the fact is the disappearance of a participant (like the mother in bornTo(mut child: Person, mother: Person)). Fires at ox check / ox build on the declaration; an endpoint whose type does not resolve is handled by the ordinary resolution diagnostics instead.
OE0268ErrorLiveRelationEndMutabilityWeakeningA relation declares an end mut while some transitive superrelation (via <: / specializes) keeps the same position immutable. Effective mutability at a position is conjunctive over the relation and every transitive superrelation: a child may tighten a parent mut end by omitting mut, but declaring mut where any applicable parent end is unmarked is refused at ox check / ox build — a child-admitted retraction would remove a subsumed parent row at an end the parent declared lifetime-bound. Remove the child mut, or mark the parent end mut at its own declaration.
OW0269WarningLiveIndividualCapturesJoinVariableA bare name used across multiple atoms of one rule body — the way a join variable is used — resolves to a declared individual, so every occurrence is that CONSTANT, not a shared fresh variable: the atoms are each pinned to the individual instead of being joined, which silently over-restricts the rule. This is the documented resolution order (a non-binder bare name that matches a fact-declared individual is that individual, workspace-wide), so the binding itself is correct; the warning flags the collision because the multi-atom shape is variable-typical and the restriction is otherwise invisible. The message names the individual, the module whose fact declares it, and the rule. Two fixes, by intent: if a join variable was meant, rename it to a name that is not a declared individual; if the constant was meant in several atoms, make the intent explicit — bind a fresh variable and pin it with an equality (s == theIndividual) — or suppress the lint on the rule. Deliberately narrow: a single-occurrence constant argument (knows(x, carol)), an equality pin, a qualified spelling (people::alice), and individual references in fact declarations, mutate bodies, and test bodies never fire. The single-occurrence collision (a would-be variable used in exactly one atom) is indistinguishable from a deliberate constant pin and is accepted silently — this warning covers the join shape only.

Stratification (05xx)

Reserved range — the stratifier’s pre-runtime aggregate diagnoses. The runtime equivalents fire as OE13xx rule-compile gates today.

CodeSeverityStatusNameMeaning
OE0510ErrorReservedNonStratifiedAggregateReserved (designed, not yet emitted as OE0510 — §7.2): a stratified aggregate that would loop through an aggregation step on its own stratum (no well-defined fixpoint). The runtime today refuses recursion-through-aggregation as OE1317 RecursionThroughAggregation at the rule-compile gate; this 05xx code is reserved for the stratifier’s pre-runtime diagnosis of the same shape.

Meta calculus, refinement, comparison, traits (06xx)

CodeSeverityStatusNameMeaning
OE0605ErrorLiveUnknownMetatypeA concept declaration’s introducer (the identifier before the concept name — pub <introducer> Name) does not resolve to a pub metatype visible in scope. Introducers are not keywords: per §3.4 the leading identifier resolves against pub metatype declarations — declared in this package or brought into scope by a use/the package prelude (§5.2). Nothing is ambient: even the baseline type (and rel for relations) must be in scope — add use std::core::{type, rel}; or list prelude = ["std::core::{type, rel}"] under [package]. Two fixes: bring the baseline into scope and use the ontology-uncommitted pub type Person;, or declare/import the vocabulary the introducer belongs to (pub metatype kind = { }; makes pub kind Person legal). Vocabulary classifiers (UFO’s kind, BFO’s class, …) are package vocabulary, not language surface — std::core’s own docs: type is the no-commitment baseline; vocabulary packages ship alternative metatypes.
OE0606ErrorLiveUnknownMetarelA relation declaration’s introducer (pub <introducer> Name(...)) does not resolve to a pub metarel visible in scope. Per §3.4 the leading identifier resolves against pub metarel declarations — declared in this package or brought into scope by a use/the package prelude (§5.2). Nothing is ambient: even the baseline rel must be in scope — add use std::core::{type, rel}; or list prelude = ["std::core::{type, rel}"] under [package]. Two fixes: bring the baseline into scope and use the neutral pub rel Owns(owner: Person, thing: Asset);, or declare/import the vocabulary the introducer belongs to (pub metarel mediation<E1, E2>(e1: E1, e2: E2); makes pub mediation Involves(...) legal). Relation-vocabulary classifiers (UFO’s mediation, material, …) are package vocabulary, not language surface.
OE0612ErrorReservedOptionComparisonRequiresHandlingRule body contains Option<T> comp_op T (or comp_op Option<T>) without explicit None-handling. Use is Some(a), a comp_op ... / `.is_some_and(
OE0613ErrorReservedTruth4ComparisonRequiresHandlingRule body contains Truth4Of<T> comp_op T without explicit four-valued handling. Use is Is(a), a comp_op ... / is Not / is Can outcome suffixes, or match { Is(a) => ..., Not => ..., Can => ..., Both => ... }.
OE0620ErrorLiveAxisValueNotInAxisDomainA rule-body value position names an axis value (rigidity::anti_rigid — a path whose first segment resolves to a visible pub metaxis declaration) that the axis’s declared domain does not admit: either the value is not a member of the enumerated domain (the diagnostic lists the declared values), or the axis declares a TYPED domain (pub metaxis weight for metatype = Real;), whose values are literals with no enumerated-symbol spelling. A valid enumerated axis value never reaches this code — it lowers to a Value::Symbol constant (owner = the axis identity, ord = the chain position) and evaluates against the catalog-closed $axis relation. (Pre-S3 this code refused EVERY axis value as not-yet-evaluable; that scope is retired — the rule-body diagnostic that remains is exactly the not-in-domain / typed-domain-spelling case.)
OE0621ErrorLiveUnknownMetaxisA metatype / metarel body binds an axis (axis: value) whose axis name does not resolve to a visible pub metaxis declaration — or matches several, in which case every candidate is named and a qualified spelling (vocab::rigidity: rigid) disambiguates. Axes are not ambient vocabulary: declare the axis in this package (pub metaxis rigidity for metatype { anti_rigid < semi_rigid < rigid };) or import the vocabulary package that declares it. Pre-S1 these bindings were parsed and silently DROPPED; now every binding resolves to the declaring metaxis’s identity and is persisted on the wire, so an unresolvable axis is a hard refusal, never a phantom.
OE0622ErrorLiveAxisValueNotInDomainAn axis binding’s value is not a member of the axis’s declared domain. For enumerated domains ({ a, b } unordered or { a < b < c } chain) the axis: value binding must name one of the declared values — the diagnostic lists them. Binding an enumerated axis with a literal (axis: 1.5), or a typed axis with a bare symbol (axis: rigid), is the same refusal: the value shape follows the domain (a bare symbol for enumerated domains, a literal for typed ones).
OE0623ErrorLiveAxisLiteralTypeMismatchA typed-domain axis binding’s literal does not satisfy the axis’s declared TypeExpr (or statically fails its where { … } refinement) — e.g. weight = "heavy" against pub metaxis weight for metatype = Real where { _ > 0.0 };. Checked statically for the primitive domains (Int / Nat / Real / Decimal / String / Bool); a refinement comparing the placeholder _ against a literal is also discharged statically. Domains the elaborator cannot decide statically are not refused here (they validate when the $axis relation materializes, slice S3).
OE0624ErrorLiveAxisTierMismatchAn axis is bound on a declaration tier its for targets do not include: a pub metaxis … for metatype axis binds only inside metatype bodies, for metarel only inside metarel bodies. Axes declared for individual / for macro currently bind NOWHERE — those binding surfaces do not exist yet, so a metatype/metarel binding against such an axis is refused with this code rather than silently accepted against a tier that can never consume it. Fix: bind an axis whose targets include this declaration’s tier, or extend the axis’s target list (pub metaxis a for [metatype, metarel] { … };).
OE0625ErrorLiveDuplicateAxisBindingA metatype / metarel body binds the same axis twice (e.g. { rigidity: rigid, rigidity: anti_rigid }) — malformed per the §4 distinct-axes well-formedness constraint (Argon.MetaCalculus.Wellformed.MetatypeDecl.axesDistinct). Axis assignment is functional per (declaration, axis): a second binding could only restate or contradict the first, so both occurrences are named and the declaration is refused. Two spellings of one axis (bare rigidity and qualified vocab::rigidity) count as duplicates — identity is the RESOLVED axis.
OE0626ErrorLiveMetaxisDeclMalformedA pub metaxis declaration’s shape is malformed: an enumerated body mixes , and < separators (a domain is either unordered { a, b } or a chain { a < b < c }, never both); the body is empty or absent (an axis with no domain admits no value, so every binding against it would be refused — declare the values or the typed domain); a value is repeated; the for target list is empty or names something other than metatype / metarel / individual / macro. The declaration is refused at ox check / ox build so the wire never carries a domain the validator cannot interpret.
OE0627ErrorLiveSymbolComparisonUnorderedAn ordered comparison (< <= > >=) over symbol values that carry no common chain order: the operands belong to DIFFERENT owners (different metaxes / different enums — chain order is per-owner), the owner declares an UNORDERED domain ({ a, b } — declare a chain { a < b < c } to compare by order), or a symbol is ordered against a non-symbol value. Emitted at ox check / ox build when both operands are statically known (axis-value / enum constants, or an axis projection whose axis identity is known); the reasoner and the mutate path refuse the same comparison at runtime under the same code — never the enum-variant-order fallback, never a silent row drop. Equality (== / !=) stays defined everywhere: symbols are equal exactly on (owner, name) identity.
OE0628ErrorLiveReflectiveProjectionSortAmbiguousA field projection base.name the sort-directed reading cannot dispatch soundly: (a) name resolves to a visible pub metaxis but the SORT of base is statically UNDETERMINED (or the body pins it to two contradictory sorts) — a Metatype-sorted base reads the metaxis through the $axis relation (meta(t).rigidity with t: TypeRef), while a TypeRef- or individual-sorted base reads a declared FIELD named name (the §5.2 kind-field walk-up); two different relations, so guessing would silently answer the wrong question; fix it by making the base’s sort explicit — annotate the head parameter (t: TypeRef / m: Metatype), or bind the base with a sort-determining catalog atom (m : Metatype, iof(t, kind), an equality with a sorted variable — Var == Var equalities propagate sorts). (b) the base IS Metatype-sorted but no visible metaxis is named name — metatypes carry axis bindings, not fields, so the $field:: join would be silently empty; declare/import the metaxis, or project the field from a type or individual. A projected name matching SEVERAL visible metaxes on a Metatype-sorted base is refused through the axis resolver’s ambiguity arm (OE0621).
OE0629ErrorLiveAxisAssignmentConflictTwo same-precedence $axis assignments disagree for one (target, axis) pair at module load (the effective axis relation is functional — a metatype binding may be overridden by a per-target meta_property event, but two conflicting assignments at the SAME precedence level have no defined winner, so the module refuses to load rather than silently pick one). No surface form double-asserts today (duplicate axis bindings refuse at OE0625; duplicate #[order] refuses at elaboration); this code is the artifact-trust backstop for hand-built or corrupted event logs. Emitted by oxc-runtime at load; declared here so appendix C and ox diagnostics carry it.
OE0630ErrorLiveIncomparableValueTypesAn ordered comparison (< <= > >=) is evaluated between two values whose types carry no common order: e.g. an Int against a Date, a number against a Text. Pre-refusal the reasoner’s value_order fell back to the derived Ord of the Value enum — comparing by variant discriminant — so a mistyped field (an Int stored in a Date field, OE0236’s runtime cousin) made field < <date> unconditionally true and field > <date> unconditionally false regardless of the actual values, silently deriving wrong rows. Now a loud ReasoningError, parallel to the existing temporal-mismatch (TemporalTypeError) and unordered-symbol (OE0627) refusals, raised in both the rule evaluator and the mutate value path — never the enum-variant-order fallback, never a silent row drop. Equality (== / !=) stays defined across types (distinct types are simply unequal) and never routes through the ordering refusal — only the four ordering operators can raise OE0630. Numeric ordering across the exact-numeric tower is defined for the Int/Real carriers (and Decimal/Money operands that ride a Value::Real/literal at evaluation): both promote to a common BigRational and compare by value. A Money/Decimal value stored as an opaque Value::Cbor carrier does NOT decode to a rational at the ordering site — it byte-compares as an unordered structured carrier and is refused (OE0630), not silently mis-ordered; ordering stored exact-decimal carriers is the recorded follow-on, not a v0 guarantee.
OE0631ErrorLiveMetarelEndpointMetatypeMismatchA relation declared via a metarel introducer (pub mediation Involves(m: Marriage, p: Person)) has an endpoint whose metatype does not match — and is not a sub-metatype of — the metatype the classifying metarel declares at that position (§4.3). A pub metarel mediation(mediator: relator, mediated: kind) requires position 0 to be relator-sorted and position 1 kind-sorted; an endpoint introduced under any other metatype (or a non-sub-metatype) is refused. The §4.3 promise — “the elaborator verifies the relation’s endpoint metatypes match the metarel’s positions” — was previously prose only: the position metatype names were parsed and discarded, so a wrong-sorted endpoint (Gustavo’s inheresIn(v: Vehicle, …) where an ability must inhere via an aspect, not a kind) checked clean. The check is catalog-driven and axis-name-agnostic — it compares resolved metatype identities, never a metatype/axis name string. A metarel position naming a primordial or a generic parameter (the stdlib rel<E1: metatype, E2: metatype>) imposes NO constraint; the gate fires only when both the position metatype and the endpoint metatype are known and incompatible.
OE0632ErrorLiveReflectionOnUnclassifiedA reflection intrinsic (meta / iof / specializes / extent) is applied to a struct- or enum-declared carrier — language-level DATA, not an ontologically-classified concept (§4.4.2). Language data carries no metatype, so meta(p) == Point over a pub struct Point is a category error, parallel to OE1016 (Truth4OfOnStruct) for the Truth4 surface. The discipline §4.4.2 leans on (“calling meta() on a struct/enum-declared value is a category error … emits a diagnostic at elaboration”) was previously unenforced — the call checked clean and a vocabulary author writing nonsensical reflection over plain data got zero feedback. Reflection applies only to concepts introduced under a vocabulary or stdlib metatype; classify the carrier under a metatype, or drop the reflection.
OE0633ErrorLiveMetarelEndpointArityMismatchA relation declared via a metarel introducer (pub mediation Involves(m: Marriage, p: Person)) has a different number of endpoints than its classifying metarel declares positions (§4.3). A pub metarel mediation(mediator: relator, mediated: kind) declares two positions, so a relation introduced under mediation must have exactly two endpoints — a ternary mediation R(a, b, c) and a unary mediation R(a) are both refused. The §4.3 endpoint-verification step zipped the relation’s endpoints against the metarel’s positions and silently continued past any position beyond the metarel’s arity, so an over- or under-arity relation checked clean (its surplus or missing endpoints were never validated). The guard is arity-EQUALITY against the metarel’s declared endpoint count — the generic stdlib rel<E1: metatype, E2: metatype> declares two positions and still accepts exactly its two endpoints; a metarel whose positions are all unconstrained (None) still requires the matching count. It is not relaxed to “accept anything”: a metarel imposing no per-position metatype constraint still pins the arity. Forward-compatible — only relaxes if metarel genericity (variadic positions) later lands. Mirrors arityEqual (Argon.Substrate.RelationSubsumption) and the OE0150 relation-arity precedent.
OE0634ErrorLiveAxisSetFormMismatchA metaxis binding uses the wrong form for its domain’s arity. A set-valued domain (pub metaxis restrictedTo for metatype = [ Nature ]) binds ONLY with the set form axis: [a, b]; a scalar domain (enumerated { … } or single Typed) binds ONLY with a single axis: value. Crossing the two — a scalar value against a set domain, or […] against a scalar domain — is refused here. This consolidates what were divergent, non-agreeing refusals for one need: a set binding against a scalar domain previously tripped OE0626 (“expects a value, found [”), and a single value against a set domain tripped OE0622 — separate codes for “you used the wrong binding shape.” OE0634 is the single FORM gate; a set MEMBER that fails the element type / refinement is OE0623 (the per-element type check), not this. Emitted at elaboration and re-checked at artifact load (a crossed form reaching the runtime is a wire inconsistency). The set form is admitted only by a set-domain axis (AxisDomainBody.admitsArgon.Storage.AxisBindingValid).
OE0660ErrorLiveRefinementUnsupportedFormA where/iff refinement predicate — a concept refinement, or the value filter of a navigation-view from clause (f: [T] from Rel.endpoint where <pred>) — contains an expression form the refinement evaluator doesn’t support. Supported forms: literals, self/identifiers, field projection self.field, binary ops (arithmetic / comparison / && / `
OE0661ErrorLiveSubqueryInComputeBodyA fn body contains an aggregate/quantifier subquery over a relation extent — exists { Rel(…) }, count { … }, forall …, sum { … }. A fn is pure compute over its arguments and has no access to a relation’s extent, so the subquery ranges over nothing and the form evaluates SILENTLY to empty/false (the fn then misbehaves wherever it is used as a rule-body predicate atom). It is therefore refused at build time rather than evaluated. This is the subquery form ONLY: a COMPREHENSION over an argument-reachable collection or from-field — count(x for x in p.coll) > 0 — is bounded by an argument value, evaluates correctly, and is NOT refused. Express the extent-scanning condition on the rule plane, where relation extents are in scope: pub derive popular(p: Person) :- p: Person, HasFriend(p, _);. Refusing at build time is mandatory: dropping the subquery would silently yield a fn that returns false for everyone — the silent-wrong failure this code exists to prevent. The bounded-root-anchored design that will evaluate an argument-rooted subquery in a fn is a separate, larger change.
OE0662ErrorLiveShapeClauseUnresolvedDeriveA concept’s shape clause (pub type C <: P iff Shape(self, …), the derived-classification form) names a shape that does not resolve to a pub derive declared in the SAME module. The clause desugars to a synthesized concept-headed rule derive C(m) :- Shape(m, …), P(m); whose body reads the shape derive’s extent, so the shape MUST be a module-local pub derive — an imported derive, a private (non-pub) derive, or an undeclared name has no extent to read and would silently classify nobody (the silent-empty failure this gate refuses). Declare pub derive Shape(…) :- …; alongside the concept, or correct the name. Imported / cross-module shapes are not yet a legal shape target.
OE0663ErrorLiveShapeClauseTargetNotADeriveA concept’s shape clause (iff Shape(self, …)) resolves to a module-local declaration that is NOT a derive — a query, fn, check, mutate, concept, or relation of the same name. Shape membership is computed on the rule plane by the synthesized concept-headed rule that reads the shape’s extent, so the shape must be a pub derive (the one declaration kind that carries a derived extent the membership rule can read). No other declaration kind carries that extent. Point the clause at a pub derive, or rename the colliding declaration.
OE0664ErrorLiveShapeClauseArityMismatchA concept’s shape-clause argument count does not match the shape derive’s head arity. iff Shape(self, w1, …, wn) requires the module-local pub derive Shape to declare exactly 1 + n head parameters: parameter 0 receives the classified individual (bound to the shape-clause self), and each of the n witnesses binds one further head column. A mismatched clause would either drop head columns silently or leave a synthesized-rule body variable unbound, so it is refused at build time rather than classifying against a malformed body. Pass one argument per shape-derive head parameter (the leading self plus one witness each).
OE0665ErrorLiveShapeClauseParamTypeMismatchThe shape derive’s head parameter 0 declares a type that is <:-INCOMPARABLE with the shape-classified concept’s declared parent — neither a subtype nor a supertype of it. iff Shape(self, …) binds parameter 0 to the classified individual, and the synthesized membership rule conjoins the declared parent (derive C(m) :- Shape(m, …), P(m);). A parameter-0 type comparable with the parent is fine: the PARENT itself or an ANCESTOR narrows the join to the parent, and a DESCENDANT of the parent already ranges within it (the conjunct is redundant, not empty). Only a type incomparable with every declared parent is refused — the join could be non-empty solely by multiple classification, almost always a modeling error that classifies nobody. An UNANNOTATED parameter 0 is accepted (nothing declared, nothing to contradict); a concept with no declared parent is accepted (nothing to bound against). Annotate parameter 0 with a type comparable to the concept’s parent, or drop the annotation.
OE0666ErrorLiveShapeProjectionHeadCollisionA rule head lands on an already-claimed shape-projection name. Each shape-clause witness synthesizes a projection derive named __classification_<Concept>_<witness>; that spelling is not injective over underscored identifiers (concept A with witness b_c and concept A_b with witness c both mint __classification_A_b_c), and Argon’s same-head union semantics would silently merge the two projections’ rows — a silent-wrong classification. The same channel opens if a hand-written derive/query claims a __classification_-prefixed head, so that prefix is reserved outright. Rename a concept, a witness, or the offending derive so every projection head is distinct.
OE0667ErrorLiveTraitImplBoundsNotSupportedGeneric-parameter trait bounds on pub trait or impl blocks are reserved syntax but not yet implemented in v0.1. The conditional-impl coherence theorem (Argon.TypeSystem.Conditional) admits multi-impl resolution under disjoint bounds; the elaborator side ships in V1. Use pub trait T<U> / impl<U> Type (without bounds) for now.
OE0668ErrorLiveRefinementInvariantViolatedA membership write would place an individual in a primitive (where) concept whose necessary invariant it positively violates — the predicate evaluates to a definite false. unknown permits the write (information absence, not violation). Checked when a primitive-where member is created by insert iof, by construction (insert T { … }), or when an update writes a field the predicate reads. Emitted by the runtime mutate path (oxc-runtime); the same exact value tower as every other value position.
OE0669ErrorLiveShapeClauseDuplicateWitnessOne shape clause names the same witness twice (iff S(self, p, p)). Each named witness mints one projection derive __classification_<Concept>_<witness>, so a duplicated name would mint the identical projection head twice and Argon’s same-head union semantics would silently merge the columns — and a duplicated binder adds no expressive power. Witness names must be distinct within a clause. To require two shape columns to be EQUAL, bind them to one variable inside the shape derive’s own body (pub derive S(c, p) :- Covers(c, p, p);) and name the witness once.
OE0670ErrorLiveImplMemberMissingAn impl Trait for Type does not provide a member its trait declares (completeness). Every trait member is an obligation: a missing rule-plane member would leave the member predicate without a clause for this target, so calls covered by this impl would silently derive nothing. Provide the member with a full body, or remove the impl.
OE0671ErrorLiveImplMemberExtraneousAn impl Trait for Type provides a member the trait does not declare, or provides it with a different signature — arity, parameter types modulo Self, return type, or plane (derive/check/query vs fn/mutate). The trait owns the member contract; an impl can neither extend it nor reshape it. Bare impls (impl Type { … }) are exempt — they carry no contract (§5.4).
OE0672ErrorLiveOrphanImplViolationAn impl Trait for Type lives in a package that declares neither Trait nor Type (§12.4’s reserved orphan rule, now real). Allowing orphan impls would let two packages give one (trait, type) pair conflicting clauses with no owner to arbitrate. Move the impl into the package declaring the trait or the one declaring the type. v0.1 compiles a single user package plus the stdlib, so this fires today only for impls pairing a stdlib trait with a stdlib type; it activates fully with multi-package composition.
OE0673ErrorLiveImplTargetsOverlapTwo impls of one trait have overlapping targets: the targets are <:-comparable, or they share a declared common descendant (coherence). Overlap would put some declared type under two clauses, so clause selection would no longer be single-valued per declared type — and specialization (“more-specific impl wins”) is rejected by design. impl T for Person + impl T for USPerson is the comparable arm (write disjoint targets, or one impl whose body branches); impl T for Person + impl T for Customer with pub type Employee <: Person, Customer declared is the common-descendant arm.
OE0674ErrorLiveSupertraitUnsatisfiedAn impl Sub for T exists but a supertrait of Sub has no impl covering T. Supertraits are requires-constraints, Rust-exact: pub trait Sub: Super makes impl Sub for T well-formed only when some impl Super for U with T <: U exists. Nothing is inherited — add the missing supertrait impl.
OE0675ErrorLiveSelfMisuseSelf is used outside the positions where it resolves. Self resolves only inside trait and impl bodies: in a trait member signature it is the obligation’s type parameter; in an impl member it denotes the impl’s target type. The full discipline: (1) Self outside a trait/impl body never resolves — it is not a module-level type; (2) a trait member signature must mention Self in at least one parameter position (a member that is not about the implementing type belongs at module level); (3) return-position Self on a query member is refused — it would make the dispatch endpoint’s type a union over impl targets, which needs union types or bounded generics (V1). Move the declaration into a trait/impl body, or replace Self with the concrete declared type.
OE0676ErrorLiveImplMemberSeverityDivergesAn impl’s check member states a severity different from the one its trait pins. A trait-side check member signature may pin its severity (check OverLimit(Self) => Severity::Error;); the pin makes the member’s blocking behavior part of the trait contract — a contract whose blocking behavior varies by implementor is a weak contract (an Error that guards mutations on one target but merely warns on another is not one obligation, it is two). Under a pin an impl may omit its payload’s severity: field (it inherits the pinned one — the ergonomic point of pinning) or restate the same severity (harmless); stating a different one is refused here, naming the trait, the member, the pinned severity, and the divergent one. Codes and messages stay per-impl. To keep per-impl severity freedom, remove the pin from the trait signature.
OE0677ErrorLiveShapeClauseMalformedA shape clause (iff Shape(self, w…)) is malformed or misplaced. The shape-clause grammar: the clause is legal only at a concept declaration’s refinement position (pub type C <: P iff Shape(self);, or the standalone pub type C iff Shape(self);); the shape path is a single module-local name (no :: segments, self::-qualification included); the arguments are parenthesized; self (the classified individual) is exactly the FIRST argument; and every remaining argument is a plain identifier naming a witness. Each refusal is loud and the parser recovers past the clause so the rest of the file still reports — nothing lowers from a malformed clause (a silently dropped clause would leave the concept unconstrained, the silent-wrong this family refuses). Exactly one refusal is reported per clause; the first malformation wins.
OE0678ErrorLiveShapeMembershipHeadClaimA hand-written rule head (a derive or check, module-level or standpoint-scoped) claims the membership rule of a shape-defined concept (pub type C <: P iff Shape(self, …)). That head’s only legal claimant is the synthesized membership rule, which conjoins the declared <: parent; under Argon’s same-head union semantics a user rule sharing the head would add members that never satisfied the shape or the parent bound, and the derived-read surfaces (derive, --extent, bodiless select) would serve them — a check-green source silently violating C <: P, with no loud writer (the write gate guards iof writes, not the rule plane). Membership of a shape-defined concept is single-source: only the synthesized rule may head it. Rename the rule’s head, or express the extra members inside the shape derive’s own body.
OE0683ErrorLiveNavViewFilteredStandoffCapableElementA where-filtered navigation view (f: [T] from Rel.endpoint where P) whose element type T has a SHAPE-DERIVED membership (iff Shape(self, …), a rule head the well-founded fixpoint can leave undefined) is refused at build, fail-closed. WHY: a filtered view stays store-local and evaluates its element-type membership eagerly, per candidate, at read-model seed time; but a shape-derived membership has no seed-time verdict, so a store-local read would either fabricate a two-valued extent (silently including or dropping a candidate whose membership is genuinely undetermined) or fail loud at runtime — a check-green / runtime-dead outcome this family never admits. The filter-free form of the same view is instead evaluated INSIDE the fixpoint, where an undetermined member surfaces as a standoff rather than being silently resolved. SCOPE: the trigger is the ability to STAND OFF, not a derived extent generally. A braced refinement (iff { P }) is derived but its predicate cannot call a rule (OE0660), so it is always two-valued and never stands off — a filtered view over such an element type is ACCEPTED and keeps its store-local materialization. REMEDY: either drop the where filter so the view lifts into the fixpoint, or make T a concept whose membership is a seed-time fact (an ordinary declared concept, a where refinement, or a braced iff), or move the narrowing the filter expresses into the element type’s own iff definition.
OE0684ErrorReservedNavViewUnproductiveCycleReserved (designed; the productivity-graph emitter is a follow-on increment). An unproductive positive navigation-view cycle: a lifted view whose extent is provably empty for every store — a view-element dependency cycle with no external seed, or an acyclic dead-end that can never produce a member. WHY: a lifted view synthesizes a fixpoint rule f(self, x) :- C(self), Rel(self, x), T(x) whose element membership T(x) may itself read back through the same view; when that dependency graph has no productive entry — nothing outside the cycle can ever assert a member — the view is empty in every model, which is a modeling defect, not a runtime standoff (a standoff is a value the consumer adjudicates; an unproductive cycle is dead code). The validation graph carries view-element edges so the productivity check catches it at build rather than serving a permanently empty view. REMEDY: break the cycle by seeding at least one element type from outside it (an ordinary concept, an asserted fact, or a membership rule that does not itself depend on this view), or remove the view if its emptiness is intended.
OE0685ErrorReservedImperativeProjectionIncomparablePinReserved (designed and wired, but not yet reachable: the imperative read-goal path does not route through the shared rule-reference resolver, so no caller selects the imperative mode and this emitter cannot fire). An imperative projection (x.field in a mutate / test body) whose bare field name resolves to two or more distinct canonical cells with nothing determining which slot is meant — the pin-resolution ladder’s Incomparable outcome. WHY: same-named fields on distinct concepts are DISTINCT storage cells (each field’s identity hashes its declaring concept’s qualified path, so Taxpayer.balance and Trust.balance never alias); when the base variable is pinned to several concepts that declare field on incomparable branches of the <:-lattice — no single declarer is a <:-ancestor of the others, so there is no most-specific cell — a bare-name read would silently pick one branch’s cell and write or read the wrong value. An imperative body cannot defer this to the fixpoint; it must name one cell. REMEDY: pin the base to the concept whose field you mean (bind it with a C(x) extent atom or an iof(x, C) for the single declaring concept), or rename one of the colliding fields so the projection is unambiguous.
OE0686ErrorLiveRuleBodyProjectionAmbiguousPinA rule-body field projection (t.field in a derive / query / check body) whose base is pinned to several distinct concepts, none of whose <:-ancestry declares a field named field, so the ladder can key no cell — the pin-resolution ladder’s Ambiguous outcome (and the cross-module incomparable case a file-local oracle cannot answer, resolved through the workspace <:-ancestry walk). WHY: same-named fields on distinct concepts are DISTINCT cells (a cell is keyed by its declaring concept); the ladder keys a concept-pinned read to the single most-specific declaring concept in the base’s accumulated pins. When no pinned concept (nor any of its ancestors) declares the field, there is no cell to key and a bare-name read would join an empty or aliased relation — a silently wrong answer. The runtime and the build-plane validator consume the SAME resolved references the checker accepted, so this refusal never diverges cross-module. REMEDY: pin the base to a concept that actually declares field (a head parameter typed to that concept, or a body C(t) / iof(t, C) atom), or correct the field name.
OW0679WarningLiveShapeClassifierNegationCycleA shape-defined concept (pub type C <: P iff Shape(self, …)) participates in a recursion-through-negation cycle across classifiers: its synthesized membership rule reaches its own extent through a negated atom (directly, or via another shape/derive whose body negates back into C). This is ALLOWED, not refused — the well-founded model gives such a cycle a value, and membership surfaces Can (well-founded-undefined) for the individuals inside the cycle rather than a definite Is/Not. The warning is loud so the modeler knows those individuals read Can (and a definite-only surface will refuse or drop them), not silently absent. This is the classifier-cycle analogue of the ordinary WFS treatment of recursion through negation; it fires ONLY for a shape-defined classifier in such a cycle, never for an ordinary rule-head concept. To get a definite classification instead, break the negative dependency between the classifiers (make the chain asymmetric / stratified).

Modules, attributes, temporal, modal, forget (07xx)

CodeSeverityStatusNameMeaning
OE0701ErrorLiveInvertedDurationA metric-temporal operator’s interval [a, b] is malformed (§7.3.2). The common case is an INVERTED interval — lower bound a exceeds upper bound b: a metric interval is a forward offset window on the valid-time axis, so an inverted interval denotes the empty window and the operator would be vacuous (emitted at lowering when both bounds are statically-known integer durations — a literal day-count, an <int>.days/.weeks sugar — and a > b; an inf/ upper bound is never inverted). Also covers an inf/ in the LOWER-bound position: only the upper bound may be unbounded. Swap the bounds, write [0, b] for an anchored window, or replace an inf lower bound with a finite offset.
OE0702ErrorReservedMetricArityMismatchUnary metric temporal operator applied to two operands (or binary applied to one) (§7.3.2).
OE0703ErrorReservedMetricAtomBelowTierMetric temporal atom appears under temporal: snapshot or temporal: none (§6.10.5).
OE0704ErrorLiveReservedIntrinsicNameA declaration is named after an IDENT-lexed intrinsic: a reflection intrinsic (implements, implementors, spec §4.4) or a determinedness test (undetermined, determined, which read whether a membership atom’s verdict was left undefined). Rule-body call forms of these names always denote the intrinsic — the reflection heads are claimed by name resolution, the determinedness tests by the atom lowering that runs before it — so the declaration would be silently unreachable, and its own call sites would be refused with a diagnostic describing the intrinsic rather than the program written. Rename the declaration. The keyword intrinsics (iof, specializes, meta, extent) cannot collide and need no gate.
OE0705ErrorLiveUnknownDirectiveAn #[...] attribute names no registered compiler directive (the directive registry). Unknown attributes never silently no-op: a typo’d directive (#[defeasable]) would otherwise silently change rule semantics — the canonical case let a felon vote. The diagnostic suggests the nearest registered directive when one is within typo distance. Macro-invocation attributes (spec section 13) are not built; until they are, every attribute must be a registered directive.
OE0706ErrorLiveDirectiveReservedUnimplementedA directive the book documents but the toolchain does not implement (#[brave], #[intrinsic], #[coinductive], …). Refused loudly rather than silently ignored: a directive that parses green while doing nothing misrepresents program semantics. The message cites where the directive is documented and what to do instead. (Removed surfaces — the #[strict]/#[defeasible]/#[defeater] strength triple and #[priority] — refuse under OE0722 instead, with a migration hint.)
OE0707ErrorLiveDirectiveInvalidPositionA registered, executed directive attached to a declaration kind it does not apply to (e.g. #[static] on a derive rule, #[comptime] on a mutate). Previously ignored silently; the registry names the directive and its valid positions.
OE0708ErrorReservedReservedAttributeNameA user pub macro or #[procmacro] pub fn declaration shadows a compiler-reserved attribute name (§9.2).
OE0709ErrorLiveAttributeArgsNotYetImplementedAttribute argument form not yet implemented; only the bare form is admitted (e.g. #[comptime], not #[comptime(strict)]). The argument syntax is parser-reserved for a future release.
OE0710ErrorReservedModuleExtractionConservativityViolationModule extractor cannot prove conservativity under the importing module’s world assumption (§3.5).
OE0711ErrorReservedModuleExtractionDefeatChainBrokenDefeat-aware extraction cannot close the defeat graph — a referenced defeater is excluded by the seed signature (§3.5).
OE0712ErrorReservedModalTemporalCrossNestRefusedModal operator nests a metric temporal operator (or vice versa) at tier: recursive. Route to tier: fol (§9.1).
OE0714ErrorReservedDirectiveConflictTwo directives from one mutually-exclusive family on a single declaration. Its only family was the rule-strength triple #[strict] / #[defeasible] / #[defeater], removed — each member now refuses individually as removed (OE0722), so a conflict never forms and this code has no live emitter. Reserved for a future exclusive-directive family rather than reused (registry hygiene).
OE0715ErrorLiveModuleHeaderReadingRemovedA content-carrying file declares mod NAME; (no sibling NAME.ar, no inline { … } body) in the legacy module-header position — the reading where the mod renamed the file’s OWN namespace. mod NAME; has a single meaning, Rust’s: it declares a CHILD module backed by a sibling NAME.ar (or NAME/mod.ar). A file cannot rename itself. Refused loudly: the silent-rename meant a typo’d mod quietly relocated a whole file’s declarations under a phantom namespace while ox check stayed green. To name a package’s module, use the directory/file layout (the root file is module root); to declare a child module, create the sibling NAME.ar; to keep declarations at the current namespace, delete the mod NAME; line.
OE0716ErrorLiveDefeatTargetUnresolvableA #[defeats(target(args))] target resolves to nothing in the attacking module’s import-scoped catalog (its own rules plus the public rules reachable through its use imports): no derive head of that name, no clause carrying that #[label], or no trait member at that @ Type impl. The message distinguishes a misspelling (no such name visible anywhere) from a not-imported name (a matching public declaration exists in a module this one does not use — add the import, or write the qualified path module::head(args)). Defeat targets are resolution-checked at elaboration (goto-def-able) so a typo never silently changes which norm a program concludes. Also covers a malformed call-form target, a bare #[defeats] with no target, and a target/head arity mismatch. The accepted forms are head(args), head.label(args), module::head(args), and Trait::member(args) @ Type.
OE0717ErrorLiveDefeatsStrictConclusionA #[defeats(...)] target resolves to a head/clause not marked #[default]. Strict conclusions are unattackable: adding rules to a classical program can only add conclusions, and defeat exists only where overridability was declared. Mark the targeted clause #[default] to make it overridable, or remove the attack.
OE0718ErrorLiveDefeatGraphCycleThe defeat graph (over resolved rule identities — clauses and heads) has a cycle, refused in v1. Cyclic attack structures are exactly where the well-behaved compilation stories diverge; v1 refuses rather than picking one silently. An exception-to-an-exception (a #[default] rule that is itself a #[defeats] target) is legal as long as the chain bottoms out. The message names the cycle rule by rule.
OE0719ErrorLiveDuplicateClauseLabelTwo clauses of one head carry the same #[label(name)]. Labels are per-head identities — head.label must address exactly one clause — so a head cannot have two clauses labeled alike. Rename one of the labels.
OE0720ErrorReservedNonUniformBridgeRefusedBridge consults facts at a different valid-time than the bridge head’s; refused outside tier: fol (§10.3).
OE0721ErrorLiveDefeatArgumentUnboundA #[defeats] target argument binds in neither the head nor the body of the decorated rule, or binds only in the body (per-tuple defeat keys on the attacker’s HEAD tuple). A directive argument is never a fresh variable — the lesson that a silently-fresh variable matched everything. Name a variable the attacker derives in its head.
OE0722ErrorLiveDeprecatedStrengthAttributeThe Governatori strength-attribute surface — #[strict] / #[defeasible] / #[defeater] and #[priority] / pub priority — is removed. It silently inverted a head’s polarity at a distance (a defeater spelled the head it denied) and numeric priority was non-compositional and silently dropped. The replacement is honest heads plus the defeat-directive plane: unmarked rules stay strict; #[default] marks an overridable clause; an exception is an ordinary rule under its own honest head carrying #[defeats(target(args))]; lex specialis is the specific rule defeating the general clause’s #[label]. No silent aliasing — migrate the program. The help text shows the new form for the specific attribute.
OE0723ErrorLiveMacroInvocationDidNotExpandA macro invocation name!( … ) survived the EXPAND phase: no pub macro name with a rule matching the invocation is in scope (the macro is undefined in this module, or none of its rules’ matchers bind these arguments). An unexpanded invocation is refused rather than silently accepted — an invocation the elaborator does not understand must not vanish from the artifact (the silent-wrong discipline forbids). Define the macro, fix the invocation to match a rule, or import the macro (cross-module macro use is a follow-up).
OE0724ErrorLiveUnknownFragmentSpecifierA macro metavariable $name:spec names a fragment specifier outside the closed v1 set. The admitted specifiers are the ontological concept / rel / metatype / rule and the syntactic expr / ident / ty / literal / path / tt; standpoint is cut from v1. Validated at expansion so a macro body never binds a metavariable against a parse category the expander cannot honor. Use one of the admitted specifiers.
OE0725ErrorLiveReservedHygieneIdentifierA user-authored identifier contains the reserved hygiene marker · (U+00B7 MIDDLE DOT). That marker is reserved for the names macro hygiene mints when freshening a macro-introduced variable, giving those names a namespace provably disjoint from anything a user can write — the disjointness the hygiene non-capture guarantee rests on. Remove the · from the identifier.
OE0726ErrorLiveDuplicateMacroDefinitionA module declares two macros with the same name. A macro name must have exactly one implementation per module (uniqueness-at-registration) — two macro name { … } declarations are a loud error, never a silent merge or shadow (the silent-wrong discipline forbids; the two rule sets would otherwise be invoked as if one macro). Rename or remove one of the declarations; a distinct cross-module macro of the same name is reached with a module-qualified use.
OE0727ErrorLiveMacroExpansionDidNotConvergeA module’s macro expansion did not reach a fixed point within the fuel budget: a macro whose expansion re-introduces an invocation of itself (directly or through a cycle) diverges. The phase stops and refuses rather than looping forever — distinct from OE0723 (an invocation that no rule matches), since here the macro does match but its expansion never settles. Break the recursion (add a non-recursive base rule, or stop the rule from re-emitting its own invocation).
OE0728ErrorLiveExpansionSpanUnanchoredA diagnostic produced over macro-expanded text carried a span that the source-faithful expansion provenance map could not resolve to any location the user wrote. This is a compiler bug: every span over expanded input must resolve to real user source (a copied-through fragment) or to the invocation site of the macro that synthesized it. The compiler refuses to render text the user never wrote, so it surfaces this internal error loudly rather than pointing at a phantom location. Please report it with the input that triggered it.
OE0729ErrorLiveProcmacroBodyNotTotalA procedural macro (#[procmacro] pub fn) body uses a construct outside the total fragment, so its termination cannot be guaranteed by construction. The procedural meta-language is deliberately a closed, strongly-normalizing fragment: let bindings over string literals / reflection projections (item.name, item.params[i].ty) / concat_idents(…) paste, a quote { … } (with $-splices and a bounded $( for x in item.fields ) { … } repetition over a reflected child-list), and a list of quote/typed-artifact elements. General control flow (if / match / for / while statements) and calls to anything other than concat_idents are refused HERE, at the declaration — totality is enforced, not trusted to a fuel cap at expansion time (distinct from OE0727, which catches a runaway at expansion). Rewrite the body within the total fragment; iteration over a declaration’s structural children is the bounded $( for … ) repetition inside quote, not an open loop.
OE0730ErrorLiveForgetWithoutCapabilityA mutate body contains forget but the enclosing mutate declaration does not grant #[allow_forget]. forget physically erases axiom events including their bitemporal history; the capability must be granted explicitly at the declaration that wields it. The richer capability plane (ox.toml / backend principal / _forget_log audit) is a recorded follow-on.
OE0731ErrorReservedForgetLogTamperAttempted forget on a _forget_log event.
OE0732ErrorReservedRetentionViolationQuery targets transaction-time outside the declared #[retention(tx_time, ...)] window.
OE0733ErrorLiveSchemaDeclInStandpointA vocabulary / schema-level declaration, or a query / mutate, appears inside a standpoint { … } block. A standpoint scopes a SOURCE’S VIEW, not a separate universe: the vocabulary it ranges over is shared and lives at module level. Standpoint-scopable is the view’s CONTENT — facts (pub fact / pub not_fact), the reading-relative rule form pub derive, and pub check (discharged in this standpoint’s view). A derive or check written lexically inside the standpoint is sugar for a module-universal rule evaluated within this standpoint’s view: it fires within this standpoint (exact-match on the standpoint id, plus DEFAULT-owned module rules) and is invisible to the base and to sibling standpoints, exactly as a module-level rule gated on a standpoint-local reading fact would. Still refused: the vocabulary declarations (pub type / pub rel / metaxis / metatype / metarel / enum / struct / trait / fn / macro), which describe the universe; query, redundant with the across [S] federated readout; and mutate, whose per-standpoint form is a recorded open question. (mod / use / test / a nested standpoint are governed by the parser.) The pattern for a refused form is unchanged: declare it at module level, then assert (pub fact) or read (pub derive / across [S]) it per standpoint. Refused at ox check / ox build, parallel to the impl-in-standpoint refusal in the same dispatch.
OE0734ErrorLiveProcmacroSignatureTypeA procedural macro (#[procmacro] pub fn) signature names a type outside the reflection vocabulary. A procmacro is a macro definition, not a value-level function: its parameters reflect the macro’s input — Decl (the decorated declaration), Args (the attribute arguments), or Syntax (a function-like macro’s token input) — and it returns Syntax (a single emission) or Expansion (a list of emissions / typed artifacts). These reflection types are the only ones admitted in a procmacro signature; an ordinary value type (or a typo) is refused here so the macro author is not silently handed a meaningless signature. Use one of the reflection types.
OE0735ErrorLiveDefeasibleScopedDeriveA standpoint-scoped pub derive carries a defeasibility marker (#[default] / #[defeats] / #[label] / #[defeasible] / #[defeater]). A scoped derive is evaluated within its standpoint’s view by the strict-classical per-standpoint path, which does NOT run the defeat-plane resolution: #[defeats] / #[label] are resolved globally (a whole-file pass with no standpoint axis, so an edge could cross standpoints), and the per-standpoint federated evaluation carries no defeat fold — so the markers would be SILENTLY INERT and the rule would fire un-defeated in its view (over-derivation). A scoped derive must be strict until per-standpoint defeat resolution is implemented; refused loudly rather than accepted as a hollow surface. Make the scoped derive strict, or move the defeasible rule to module level.
OE0736ErrorLiveDefeatTargetAmbiguousA bare #[defeats(head(args))] short name resolves to a public head in more than one imported module, so the attack does not determine which rule it overrides. The message names each candidate’s module; disambiguate by writing the qualified path module::head(args) (or module::head.label(args) for a clause-level target), which resolves the head against exactly the named module. Own-module declarations shadow imported ones, so ambiguity only arises between imports.
OE0737ErrorLiveDefeatTargetNotVisibleA #[defeats] target resolves to a declaration that exists in another module but is not pub, so the attacking module cannot name it. Defeat visibility equals ordinary name visibility: the set of modules that can attack a rule is exactly the set that can name it, a bound the rule’s author already controls with pub. There is no action-at-a-distance on private rules — a private rule’s conclusions must never silently depend on code its author cannot see. Only the target’s own author can expose it by making it pub.
OE0738ErrorLiveDefeatCrossPackageRefusedA #[defeats] target resolves into a different package. A defeat edge may cross module (file) boundaries only within one package: a package is a trust and versioning boundary, and a cross-package edge would let a dependency update silently change the program’s conclusions — a new version could add an edge overriding one of your defaults, or change which clause your edge resolves to, with no change to your source. Compose across packages through ordinary use of public predicates (honest heads), which is strategy-independent and unaffected by this rule.
OE0739ErrorLiveDefeatComponentStrategyConflictA connected defeat component spans modules that selected incompatible reasoning strategies. A connected defeat graph is compiled together by one strategy’s transform (single strategy per connected defeat graph — the invariant the file boundary used to guarantee by construction, now checked at workspace assembly and owned by the connected component). The message names the two modules and their strategies. With one strategy in the language this refusal is unreachable in practice; it is specified and enforced from day one so a second strategy arrives against an already-guarded grain.
OW0710WarningReservedOrphanModuleFileReserved (no emitter): an .ar file under the package source root reached by no mod/use chain from the entry is not part of the package (Rust module semantics, §3.1) — not compiled, not checked, not linted. Argon matches Cargo and says NOTHING about such a file: an unreferenced source file is simply not compiled, not surfaced as a warning. The orphan set is still computed (the workspace records it; a future tool may surface it as an editor hint), so the code is held rather than retired. Declare the file with a mod item from a reachable module to include it.
OW0740WarningLiveMutualDefeatCycleUndefinedA set of #[default] public heads forms a mutual-defeat cycle: each head’s live attacker derives, in turn, from that same head through its positive support (a rule-dependency negative cycle through defeat). This is NOT the identity cycle of two heads directly defeating each other (refused earlier by OE0718) — the defeat graph here is acyclic. Such a cycle has no stable two-valued warrant, so under the well-founded semantics these heads are UNDEFINED (neither definitely true nor definitely false) and surface as Can rows rather than a definite Is/Not. This is the canonical semantics, not an error — no evaluation order changes it. The warning names the mutually-defeating heads so an author expecting a definite verdict knows they read Can. To get a definite classification, break the cycle: remove or redirect one attack so no attacker’s derivation reads back through its own target. A strict base clause settles only the tuples it covers (those become definite, and definite verdicts cascade around the cycle for them); the cycle — and this warning — remain for every other tuple.
OW0741WarningLiveCollisionCapableSiblingsTwo sibling relation members translate identically onto the same parent family: both are subsumption children of one parent, and their resolved argument mappings onto it are byte-identical, so they share the same image under the mapping φ. A fact of one member and an identically-shaped fact of the other translate to the same parent tuple, and because a relation’s extent is a set, those images collapse to a SINGLE parent row — an aggregate over the parent counts the shared row once, not twice (two members each asserting (alice, 500) yield one parent row, so sum(amount) is 500, not 1000). This is the correct set semantics, so it is a WARNING, not an error; it is surfaced because it is almost always a modeling slip. The warning names both members and the parent. Fix, in order: (1) if the members are distinct families, give them distinguishing translations onto the parent — a constant pin that differs, or a discriminating parent end each fills differently — so their rows stay apart; (2) if they are the same family, declare one member, not two.
OW0742WarningLiveDuplicateFactInFileAn identical pub fact — same relation, byte-identical argument list after canonical encoding — is asserted more than once in the SAME source file. A relation’s extent is a set: the second assertion adds nothing, the two identical assertions collapse to one row, so an in-file literal repeat is almost always a copy-paste error. This is a WARNING, not a refusal — the program is well-defined (the repeat is idempotent). Two remedies, in order: delete the duplicate assertion if it is a copy-paste error; OR, if the repeats are meant to record DISTINCT events (a fact stated twice because it happened twice), give each fact its own identity — add an event-id end so the arguments differ and both rows survive. (Argon facts assert propositions, not events; a bare proposition is true once, no matter how many times it is written.) The lint is deliberately narrow: it fires ONLY on same-file literal duplicates. It stays silent for the same fact asserted across two different files (a module legitimately restating a shared proposition) and for a duplicate arriving through a mutation (an insert of an already-present fact re-freezes the existing row — a defined no-op on the mutability plane, not an authoring slip).
OW0743WarningLiveDeclarationShadowsImportA derive, rel, or concept declaration’s bare name is already bound by an explicit use import in the same module, and that import resolves to a predicate declared elsewhere. Head declarations are module-local and bare-name resolution is local-first, so this declaration introduces a NEW module-local predicate that shadows the imported one: clauses on it contribute to the module-local predicate, NOT to the imported one — reads of the imported predicate silently miss the intended tuples, and an unqualified read from a third module refuses as ambiguous far from the cause. This is a WARNING, not a refusal — the program is well-defined — but the shape is almost always a modeling slip (the import of the very name being declared signals intent to share). The message names both fully-qualified predicates. Fix, in order: (1) rename the module-local predicate and wire it centrally — a rule beside the original declaration reads the renamed local predicate into the shared relation; (2) declare a distinct subrelation of the imported predicate (pub rel Local(…) <: Imported) and contribute clauses to that; (3) if a disjoint module-local predicate really is intended, remove the imported name from the use (or qualify reads of the foreign predicate) so the shadowing is explicit. The warning is deliberately narrow: it fires only when the same module both explicitly imports the name (a plain, non-glob, non-aliased use leaf) and declares it; the module declaring the original predicate never fires, and a local declaration with no matching import never fires.
OW0744WarningLiveCheckNotExhaustiveOverUndeterminedA check body that uses the determinedness test undetermined(...) / determined(...) does not cover every membership atom whose UNDEFINED (Can) verdict can leave the check’s firing verdict undecided. The named membership atom’s Can path is routed by no body clause, so the honesty gate’s severity-derived default governs it: a Severity::Error check blocks that path (OE1430), a Warning/Info/#[observe] check reports it at undefined grade, and an => emit check does not emit it. The coverage analysis is syntactic and its scope is bounded: it inspects a check’s top-level body atoms and treats a membership as standoff-capable only when the concept is computed in the same file (a derive head or an iff concept). Inside that scope it warns whenever it cannot see a routing clause, so a warning costs at most one explicit clause; a membership over a concept computed in another module is outside the analysis and takes the default without a warning. The warning is an aid to reading a body — the gate’s enforcement does not depend on it. Remedies: add a clause disposing of the named atom’s undetermined case — undetermined(A) => ... to route it, or determined(A) as a positive guard so the check does not fire on its Can verdict; OR, if the gate’s default is the intended disposition for that path, suppress this lint. This warning never blocks a build.

Field modifiers, world-assumption gates, construction (08xx)

CodeSeverityStatusNameMeaning
OE0810ErrorReservedWorldAssumptionTemporalIndex#[world(...)] declared per concept with a valid-time scope but no standpoint context (§6.9).
OE0811ErrorReservedPersistenceMarkerOnNonTemporalRulePersistence marker applied to a rule outside the temporal substrate.
OE0812ErrorReservedDefeasibleDefeaterOfDefeasibleTemporalDefeasible defeater of a defeasible temporal rule; route to unsafe logic (§7.8).
OE0820ErrorLiveUpdateImmutableFieldAn update target: T set { f = … } writes to a field f that T declares without the mut modifier. The elaborator validates each field-assignment against the field-decl’s mut flag and refuses at build time, not at mutation invocation. Emitted by the mutate-body lowerer (oxc-instantiate); a bare (un-annotated) target defers to the runtime rather than emitting here.
OE0822ErrorReservedMutOnDerivedFieldReserved (designed — §5.1): a mut modifier on a from-navigation-derived field, which is contradictory — a derived field has no independent value to mutate. mut is otherwise orthogonal to the other field-decl modifiers (#[intrinsic], defaults, metatype rigidity). This entry reserves the code for that gate.
OE0831ErrorLivePositionalInsertArityMismatchA positional insert C(a, b, …) targets a concept C. The mutate-body lowerer only routes the brace form insert C { field: … } to construction, so a positional concept insert silently constructs nothing; it is refused at check. The diagnostic names the required fields in constructor order and (on an arity mismatch) reports the argument-vs-field counts. Emitted by the driver’s mutate-body validation (oxc-driver). Use the brace form insert C { field: … } to supply fields by name.

World-assumption conservativity (09xx)

Reserved range — the §6.9 world-assumption gates are designed but not yet wired.

CodeSeverityStatusNameMeaning
OE0901ErrorLiveMixedWorldAssumptionConflictA rule or query applies negation-as-failure (not R(..)) to a FOREIGN relation (one mapped to a store by [placement.R]) whose source is read open-world — the CWA-importing-OWA boundary. A foreign relation is materialized into the fixpoint as a frozen CLOSED-world slice (the frozen-EDB rule), so not R(..) reads absence-in-the-slice as definite-false; but absence of a tuple in an OPEN-world source is UNKNOWN, not false (§6.9), so the negation reads unknown as definitely-false and over-asserts its head. The closed-world lifting of the slice into the open consumer is not provable — the TypeSystem/Soundness/CwaOwa.lean conservativity theorem proves the CWA→OWA transfer sound in one direction only — so the negation is refused at ox check / ox build rather than silently evaluated, the C6×D4 hinge (a CWA relation admits NAF; an OWA one does not). To resolve: mark the relation’s source closed-world (so absence IS falsity and not R is sound), or restructure so the foreign relation is not negated. The native-concept analog — NAF over a #[world(open)] concept’s own derived extent — is the separate OE1367 gate (the evaluator threads it three-valued); this code is the federation boundary, where the frozen slice is a closed snapshot of an open source.
OE0903ErrorReservedWorldAttributeOnStructReserved — superseded by OE0707: #[world(...)] applied to a struct/enum, which carry no ontological classification — world assumption applies only to classified concepts. The world directive is now registered concept-only (positions: [CONCEPT_DECL]), so a struct/enum placement refuses via the generic placement gate OE0707; this bespoke code is retained as a reserved row and does not fire.
OE0904ErrorLiveRecursionThroughForeignSourceA FOREIGN relation (one mapped to a store by [placement.R]) is consulted inside a RECURSIVE rule that also derives that relation’s own demand — recursion through the foreign source (the single-fetch federation boundary, §6.9). A foreign relation is materialized into the fixpoint by FREEZING it once at the EDB-loading edge: a single fetch, complete iff the relation’s extension is independent of the IDB computed in that fixpoint. When the relation appears in the body of a rule whose head is in a recursive strongly-connected component AND that body also references a predicate of the same component (the recursive back-edge), each fixpoint iteration derives new bindings that demand MORE of the foreign source than the single fetch retrieved — so the fixpoint silently under-derives. The freeze-soundness condition is mechanized as AvoidsVocab (Reasoning/Datalog/AnalyticalFreeze.lean): the producing program must not feed back into the frozen output. A non-recursive join with a foreign relation, or a foreign relation that only SEEDS a recursion (consulted once with ground demand, in a base-case rule with no back-edge), is sound and admitted. To resolve: restructure so the foreign source is a leaf strictly below the IDB it feeds (move it out of the recursive component), or wait for monotone bounded re-consultation (the orchestrator iterates demand rounds against an idempotent, demand-monotone connector — a named, gated follow-on, not a v1 capability).
OW0902WarningReservedWorldAssumptionImplicitReserved (designed — §6.9): default_world omitted from ox.toml, so the substrate applied a default world assumption rather than an explicit modeler choice. The warning that would suggest making the choice explicit is unbuilt; this entry reserves the code.

CWA evaluation and field intent (10xx)

CodeSeverityStatusNameMeaning
OE1014ErrorLiveRequiredFieldUnassertedUnder the closed-world default (book §6.9 — CWA everywhere today), a required field’s value is not derivable from any asserted axiom: the schema declares the field present but the KB does not assert it. Emitted by the runtime mutate path (oxc-runtime) at exactly one site: the in-body insert iof(x, T) construction-completeness gate — classifying x into T whose required fields x lacks, when the same body also populates fields of x, refuses atomically, judged at body end so insert iof; update set { … } in one mutation is complete (read-your-writes). Distinct from brace construction (insert T { … } missing a field → OE0207). Staged construction (classify in one mutation, populate later — no in-body field writes) currently emits NO diagnostic: the absent required field reads as K3-unknown and collapses to CWA-false at access. The field-access-time / evaluation-channel emitter that would surface staged incompleteness is designed and is not built in v0. #[world(open)] is a live concept attribute; the permit-as-unknown softening of this required-field gate under an open-world concept is designed and not yet wired.
OE1016ErrorReservedTruth4OfOnStructTruth4Of<T> field type appears on a struct (no metatype classification). The four-valued surface is restricted to metatype-classified concepts (pub type ..., or a declared vocabulary introducer).
OW1015WarningReservedOptionalFieldAmbiguousIntentReserved (no emitter): an optional field field: T? does not record whether its optionality is structural (the value may legitimately be absent) or epistemic (the value exists but is unknown), a distinction drawn from JPA’s TBox/SHACL split. The intent-marking surface and the warning that would request it are unbuilt — the #[intent(...)] attribute does not exist yet (the lint-level #[allow(...)] / [lints] suppression surface does, and this code is wired to the optional-field-ambiguous-intent lint, so the warning will be suppressible the moment it gains an emitter). This entry reserves the code for that future surface; today every T? field checks clean.

Bridges (11xx)

CodeSeverityStatusNameMeaning
OE1101ErrorReservedBridgeCycleThe bridge graph (nodes = standpoints, edges = bridges) contains a cycle that prevents stratified evaluation. Cycles between standpoints under bridge composition would require fixed-point recomputation across the federation; v0.1 admits only acyclic bridge graphs. Either break the cycle (drop one of the bridges) or wait for the V1 #[managed] bridge surface (spec §10.3).
OE1102ErrorLiveBridgeNotEvaluatedA pub bridge declaration (§10.3). Bridge rules parse, lower to BridgeDecl wire events, and resolve, but the federation fixpoint never fires them (Module::bridges_targeting has no callers) — a built artifact’s bridge bodies would silently never contribute to their target standpoint. Refused at ox check / ox build rather than building an artifact whose declared inference is inert. Bridge evaluation is the post-stable flagship standpoint deliverable; the parse / lower / wire / decode surface is retained so the work resumes without a grammar or wire-format change. Model the cross-standpoint inference with an explicit derive / pub fact for now.
OE1103ErrorLiveUndeclaredStandpointInAcrossA pub query … across [ … ] clause names a standpoint that is not declared in the workspace. Under the standpoint visibility composition rule (§10.4), a federated query reads the named standpoints’ views info-joined with the DEFAULT layer; a name that resolves to no standpoint declaration would silently contribute the DEFAULT layer alone (an empty per-standpoint extent), masking the typo as a real — but wrong — federation result. The query is refused loudly at dispatch naming the unknown standpoint. Declare the standpoint, or correct the name in the across clause. Mechanization: Argon.Visibility (the visibility relation the federated materializer honors).
OE1104ErrorLiveModalNotEvaluatedA box / diamond modal atom (§11.2) that the engine cannot soundly evaluate. The forward-rigidity discharge box/diamond(x : T) → x : T is sound ONLY when T is introduced by a fixed metatype (§10.2: fixed classification is decided at construction, so membership is frame-rigid — box φ, diamond φ, and φ coincide). The modal wrapper is then dropped and the inner classification atom is evaluated directly. Every OTHER shape is refused at ox check / ox build rather than silently stripped to the inner atom: a non-fixed classifier (whose membership can change across worlds), a non-classifier predicate P, a negated inner box(not (x : T)), and any standpoint-frame box/diamond (worlds = standpoints, accessibility = the <: reflexive-transitive closure, §10.4). The standpoint-frame Datalog translation and the tableau model engine over a Kripke carrier (§10.3) are later slices; until they land a non-dischargeable modal atom is refused loudly, because stripping it to its inner atom would be a wrong answer for anti-rigid or dynamic classification. Either introduce the classified type via a fixed metatype (pub fixed metatype kind = { … }; then pub kind T;) so the discharge applies, or model the cross-world inference with an explicit derive / pub fact for now.

Build composition and .oxbin validation (12xx, §16)

CodeSeverityStatusNameMeaning
OE1201ErrorLiveInvalidMagic.oxbin magic header does not match \0oxbin\0\1.
OE1202ErrorLiveIncompatibleVersionAxisMajor bump on one of the four version axes (oxbin_format_version, core_ir_version, tier_ladder_version, runtime_contract_version).
OE1203ErrorLiveUnknownMandatorySection.oxbin carries a MANDATORY-flagged section type the runtime does not recognize.
OE1204ErrorLiveTierMismatchArtifact’s max_tier_claimed or max_temporal_claimed exceeds the runtime’s supported maxima.
OE1205ErrorLiveArrangementSectionUnsupportedMVP runtime refuses an .oxbin carrying a DBSP-shape arrangement-section.
OE1210ErrorLiveSymbolResolutionFailedLayer-2 validation: a reference in events / rules / queries / mutations did not resolve to a symbol-table entry.
OE1211ErrorLiveStandpointLatticeCycleStandpoint lattice has a cycle (compose-time or load-time).
OE1212ErrorLiveProvenanceNotDNFAn event’s derivation column is not a well-formed PosBool(M) DNF.
OE1213ErrorLiveCompositionSignatureMismatchStored composition_signature does not match what its four legs compute.
OE1214ErrorLiveTierTableInconsistentA rule’s tier in tier-table exceeds the artifact’s max_tier_claimed.
OE1215ErrorLiveDocLinkUnresolvedA DocBlock cross-link does not resolve; strict policy fails, lenient warns.
OE1220ErrorLiveUnknownAxiomKindEvents section carries a variant tag the runtime does not recognize.
OE1230ErrorLiveTierCapExceededCompose-time: a declaration’s classified decidability tier exceeds the workspace ceiling set by [lattice].max_tier in ox.toml (§10). The ceiling is the highest of the seven ladder tiers (structural, closure, expressive, recursive, fol, modal, metaorder) a package admits; a rule the §10 classifier places above it is refused at ox check/ox build rather than emitted into an artifact that claims a tier it exceeds. Raise max_tier, or rephrase the declaration into the admitted fragment.
OE1240ErrorLiveDependencyVersionUnsupportedAn ox.toml [dependencies] entry uses a registry/VCS form — a bare version string (dep = "1.0") or one of the version/git/branch/tag/rev/registry keys — that is not yet supported. v1 supports path dependencies only (dep = { path = "../dep" }). The form is recognized and refused feature-named, not silently ignored: a version requirement that silently resolved to nothing (or to a path) would be silent-wrong. Use a path dependency, or wait for the registry story.
OE1241ErrorLiveDependencyNameMismatchAn ox.toml [dependencies] key does not match the [package].name of the package at the declared path. The dependency name is the path root the consumer uses (use dep::X;, dep::X), and v1 keeps the dependency’s published name authoritative (Cargo’s default). Rename the [dependencies] key to the package’s published name, or fix the path.
OE1242ErrorLiveDependencyCycleThe [dependencies] graph contains a cycle. Package dependencies must form a DAG; a cycle is refused loudly naming the cycle path (a -> b -> a). Break the cycle — extract the shared surface into a third package both depend on.
OE1243ErrorLiveDuplicateDependencyNameA dependency name collides as a path-resolution root: either the same name resolves to two different package directories across the dependency graph, or it equals an intra-package top-level module name. A name is a single namespace root; it cannot denote two things, and a bare name::X must not silently prefer one. (Two declarations resolving to the SAME canonical directory are de-duplicated, not an error.) Rename the conflicting dependency or the local module.
OE1244ErrorLiveDependencyPackageLoadFailedA path dependency could not be loaded: the path does not point at a directory with an ox.toml, the dependency’s entry/module closure failed to resolve, or its manifest did not parse. The dependency is refused naming the path and the underlying cause rather than silently contributing nothing.
OE1245ErrorLiveMappingSchemaDriftA compiled placement/mapping artifact pins to a Schema composition signature that does not match the schema it is being loaded against. The mapping compiles to a content-addressed artifact hashed against the schema’s composition signature, so a schema change that the mapping was not recompiled against is a LOAD-TIME refusal rather than a runtime surprise: a relation could otherwise be mapped to a store under a shape the schema no longer has. Placement is versioned separately from the schema — a relation can move stores without a schema bump — but the mapping always pins to the schema hash it was compiled against. Recompile the mapping against the current schema (ox build).
OE1246ErrorLiveForeignRelationAlsoDerivedA relation is BOTH mapped to a foreign store by a [placement.<rel>] section AND produced by a derive rule. A relation’s extent must have a single origin — it is EITHER extensional (its rows live in the foreign store the placement points at) OR intensional (its rows are computed by rule derivation) — never both. Allowing both would silently produce an ambiguous extent: the foreign rows and the derived rows would compete, and which one a query reads would depend on evaluation order rather than on the model. The conflict is refused at build time naming the relation, rather than emitting an .oxbin whose foreign-vs-derived extent is undefined. Either drop the derive rule (the relation is foreign-owned) or remove the [placement] (the relation is rule-computed).
OE1247ErrorReservedConflictingPlacementReserved (designed, not yet wired): a relation has a placement declared from two sources at once — e.g. an ox.toml [placement.<rel>] section AND a source-level foreign!/#[foreign] macro, or the same relation placed twice. A relation may be bound to at most one store; two placements would compete for which store backs the relation’s extent, and which one wins would depend on merge order rather than the model. The placements are unioned at build time (MappingSections::merge_placements) and a relation appearing in more than one source is refused, naming the relation, rather than silently overwriting one with the other. The union seam exists; the build path that emits this code on a macro-emitted-vs-config collision is wired when the macro emission surface lands. Keep a single placement for the relation — either the ox.toml section or the macro, not both.
OE1248ErrorLiveWorkspaceInheritanceUnavailableA [package] field uses the workspace-inheritance form { workspace = … } but there is no enclosing [workspace] to inherit from, or the value is workspace = false. Per-field inheritance (version.workspace = true, edition.workspace = true) is meaningful only for a member of a workspace whose root declares the shared [workspace.package] field. Set workspace = true inside a real workspace, or write the value literally.
OE1249ErrorReservedUnknownEditionReserved (no emitter) — edition-value validation deferred until editions gate surface syntax. Editions are non-negative integers, opt-in per package, parse-time-only and inert in v1: the resolved value gates nothing downstream, so any integer (given as edition = 1 or the legacy string edition = "1") is accepted. This code is held so that once an edition gates real surface syntax, an edition this toolchain does not understand can be refused feature-named rather than silently treated as the default.
OE1250ErrorLiveWorkspaceMemberVersionUnsatisfiedA workspace member depends on a sibling member (or a path dependency) whose declared [package].version does not satisfy the depending package’s SemVer constraint. A member-to-member dependency resolves LOCALLY to the sibling member directory — never to a registry — so the sibling’s declared version must satisfy the constraint, or the workspace is internally inconsistent. Align the member version, or relax the constraint.
OE1251ErrorLivePatchTargetUnsupportedA root-only [patch.<source>] entry targets a registry/VCS source that is not yet supported. v1 patches only path/workspace sources; a registry patch is refused feature-named rather than silently ignored, since the registry does not yet exist. Patch a path/workspace source, or wait for the registry story.
OE1252ErrorLiveWorkspaceMemberGlobEmptyA [workspace] members glob matched no package directory. A member glob must resolve to at least one directory holding an ox.toml; an empty glob is refused rather than silently producing a member-less workspace (a typo in members = ["crates/*"] would otherwise drop every member without a word). Fix the glob, or remove it.
OE1253ErrorLiveWorkspaceMemberGlobMalformedA [workspace] members/exclude/default-members glob is malformed: an invalid glob pattern, or an unreadable matched path. The pattern is refused naming the glob and the underlying cause rather than silently expanding to nothing.
OE1254ErrorLiveWorkspaceInheritedFieldMissingA workspace member inherits a field with <field>.workspace = true (or <dep>.workspace = true) but the workspace root’s [workspace.package] / [workspace.dependencies] does not declare that field. Inheritance pulls the shared declaration from the workspace root; if the root does not declare it, there is nothing to inherit. Declare the field under [workspace.package] / [workspace.dependencies], or give the member a literal value.
OE1255ErrorLiveWorkspaceDependencyOverrideA workspace member inheriting a dependency with <dep>.workspace = true overrides a field of the inherited [workspace.dependencies] declaration beyond what is permitted. A member may add only optional / features over the inherited declaration (additive); it may not redeclare the source (path/version/git/…). Drop the override, or stop inheriting and declare the dependency in full.
OE1256ErrorLiveWorkspaceDefaultMembersEmptyA [workspace] default-members list resolved to no package directory. A declared default-members must name at least one existing member; a list that matches nothing is refused rather than silently building an empty default set (a typo would otherwise drop every member without a word). Fix the default-members entries, or remove the key to default to all members.
OE1260ErrorLiveLockfileMalformedAn ox.lock lockfile failed to parse. The lockfile is the machine-generated record of the resolved package graph; a hand-edited or truncated lock is refused naming the parse cause rather than silently regenerated, since silently overwriting a corrupt lock would hide a merge conflict or a botched edit. Delete the lock to regenerate it (ox build), or fix the malformed entry. The lockfile is auto-generated — do not edit it by hand.
OE1261ErrorLiveLockfileContentHashMismatchA package’s recomputed content_hash does not match the value recorded in ox.lock. The lock pins each resolved package to a deterministic BLAKE3 hash over its source (the .ar files plus a normalized ox.toml); a mismatch means the on-disk source changed under a committed lock. Outside --locked/--frozen the lock is refreshed automatically on the next resolve; under --locked/--frozen it is a loud refusal, because a CI build must not silently build different source than the lock pins. Re-run without --locked to refresh the lock, or restore the pinned source.
OE1262ErrorLiveLockfileDriftThe resolved package graph does not match the committed ox.lock under --locked/--frozen: a package was added, removed, or its version/source/content_hash changed since the lock was generated. --locked requires the lock to already describe the resolution exactly and refuses to regenerate it, so drift is a loud refusal rather than a silent rewrite — the strict-CI contract that the build matches the committed lock. Re-run without --locked to update the lock, then commit the updated ox.lock.
OE1263ErrorLiveLockfileMissingNo ox.lock exists at the workspace root, but --locked/--frozen was requested. These flags require a committed lockfile to verify the resolution against; in their absence there is nothing to honor, and silently generating one would defeat the strict-CI guarantee that the build matches a reviewed lock. Run ox build (or ox check) without --locked once to generate and commit ox.lock, then re-run with the flag.
OE1264ErrorLiveUnresolvableDependencyGraphThe dependency graph has no solution: there is no single assignment of one version per package that satisfies every requirement. Argon resolves each package name to EXACTLY ONE version graph-wide — unlike Cargo, it never lets two semver-incompatible versions of the same package coexist under name-mangling, because two concepts at one qualified path cannot both be ‘the’ type (the nominal-identity invariant). So two requirements that pin the same package name to disjoint version ranges are an unsatisfiable conflict, refused loudly rather than silently mangled into coexistence. The diagnostic carries the PubGrub derivation chain — the root-cause sequence of ‘because A depends on B and C requires not-B’ steps that proves no solution exists. Relax a version constraint, align the conflicting requirements on a shared version, or drop one of the conflicting dependencies.
OE1265ErrorLiveRegistryFetchFailedA registry read failed: a transport/network error, an unreadable file:// index path, a malformed index record, or an offline build with no warm cache entry. The registry is a static content-addressed store (a config.json plus an append-only NDJSON sparse index over https:///file://); a read that cannot answer is refused loudly rather than treated as an empty result, because a silently-empty index would resolve a real dependency to nothing (silent-wrong). Check the registry URL/path is reachable, or build --offline against a warm cache.
OE1266ErrorLiveRegistryContentHashMismatchA fetched package artifact’s BLAKE3 hash does not match the cksum the registry index recorded. The content hash is the artifact’s content-address: a mismatch means the artifact is corrupt, truncated, or tampered. This is a FAIL-CLOSED refusal — the artifact is never cached or built, so a bad registry object cannot enter the build. Re-fetch; if the mismatch persists the published object is bad. (Cryptographic signatures over the artifact are out of scope; v1 integrity is the content hash only.)
OE1267ErrorLiveNoRegistryConfiguredA registry dependency is declared but no registry is configured. A bare version requirement (dep = "1.0") or a { version = "1.0" } form that names no local workspace member is a REGISTRY dependency — it resolves against a configured sparse index. This REPLACES the old OE1240 ‘registry form reserved for later’ refusal: the form is supported now, it just needs an index. Add a [registry] table to ox.toml (index = "file:///path" or index = "https://…"), or set ARGON_REGISTRY; to depend on a local checkout instead, use a path dependency (dep = { path = "../dep" }).
OE1268ErrorLiveRegistryPackageNotFoundThe package — or a version satisfying the requirement — is not in the registry index. The sparse index has no record file for the package name, or the version requirement matches no published version. Refused loudly rather than resolved to nothing. Check the package name and the version requirement, and that the package has been published to this registry.
OE1269ErrorLiveRegistryYankedVersionSelectedThe only version satisfying the requirement is yanked, and the requirement is not an exact pin. A yanked version is withdrawn from new resolutions — it stays selectable only when pinned exactly (= x.y.z), e.g. from an existing ox.lock that already pinned it, so a yank never breaks a locked build but is not picked for a fresh resolve. Pick a non-yanked version, or pin exactly if you must depend on the yanked one.
OE1270ErrorLiveRegistryArtifactTooLargeA registry body (an index record or a package artifact) exceeds the transport’s hard size cap. A registry read buffers the whole body before its content hash can be checked (OE1266 only protects AFTER the body is in memory), so an unbounded body is a denial-of-service: a malicious or buggy registry can exhaust memory or hang the build on a slow drip. The cap (a build-time constant, 256 MiB — far above any plausible published SOURCE package) is a hard refusal, not a truncation, and is enforced both before the download (when the index declares a size over the cap) and during it (the read itself is bounded); the server’s Content-Length is never trusted. If a package is legitimately this large, the cap must be raised deliberately.
OE1271ErrorLiveRegistryInvalidPackageNameA registry dependency name is not a valid package identifier. A package name is used VERBATIM as a filesystem path segment — the index shard path and the content-addressed cache path under ~/.argon — so it must match [A-Za-z0-9_-]+ (non-empty, ASCII alphanumerics plus _ and -): no path separators, no ./.. components, no empty string. A name like ../../tmp/x would otherwise escape the cache root and write outside it; this is validated at the manifest boundary, before the name reaches any path join, and refused loudly rather than silently traversing. Fix the dependency name in ox.toml.
OE1272ErrorLivePublishManifestInvalidox publish refused because the package manifest is not publishable. A published package’s ox.toml must declare a [package] table with a non-empty name matching the registry charset [A-Za-z0-9_-]+ and a parseable [package].version — the index keys a version record by exactly that (name, version). A missing/empty name, a name with a path separator or .. (which would escape the index shard / cache path), or an absent version is refused loudly rather than published under a guessed coordinate. Fix [package] in ox.toml.
OE1273ErrorLivePublishVersionExistsox publish refused because <name>@<version> is already published to this registry. The sparse index is APPEND-ONLY and every published artifact is immutable (content-addressed): a version is published exactly once and never overwritten, so a re-publish of the same coordinate — which would silently change what a downstream lock already pinned — is a hard refusal, not an in-place mutation. Bump [package].version and publish the new version; to withdraw a bad version use a yank (an append-only event), never an overwrite.
OE1274ErrorLivePublishRegistryWriteFailedox publish could not write to the target registry. v1 publishes to a LOCAL / file:// registry only — it writes the content-addressed blob under blobs/, appends the version record to the package’s NDJSON index shard, and ensures config.json — so the target must be a writable local directory or file:// URL. Publishing to an https:// production CDN registry needs upload + auth and is out of scope for v1. Check the registry path is a writable local directory, or point --registry / [registry].index at a file:// path.
OE1275ErrorLivePublishEmptyPackageox publish refused because the package has no publishable source. A package directory must hold an ox.toml and at least one .ar source file — an empty package (no .ar files), or a path that is not an Argon package directory at all, is refused loudly rather than publishing an empty artifact that would resolve to nothing downstream. Add source, or publish the correct package directory.
OE1276ErrorLivePublishBreakingChangeox publish refused because the new version makes a BREAKING change to its pub declaration surface without the breaking-tier SemVer bump. Argon recomputes the constructs semantic signature of both the version being published and the latest previously-published version of the same package, diffs them per declaration, and classifies each change against the compatibility taxonomy — proven sound in the scratch-Lean oracle (binary-compatibility, JLS Ch.13 analog): a COMPATIBLE change (a new pub decl, a widened bound/refinement, grown <: parents, widened cardinality) may publish as a patch, but a BREAKING change (removing/renaming a pub decl, narrowing a refinement — including adding a not P (NAF) clause —, an arity / position-type change, narrowing cardinality, or a not-clause-bearing closed→open (CWA→OWA) world flip) requires the breaking tier: a MAJOR bump in 1.x+, a MINOR bump in 0.x (Cargo’s 0.MINOR.PATCH rule — a 0.MINOR bump is the breaking tier pre-1.0). This is refused loudly, naming the offending declaration(s), the kind of break, and the required bump, rather than silently publishing a version a downstream ^-range would auto-adopt and then fail to resolve/check against. Bump [package].version to the required tier, or make the change compatible. The first-ever publish of a package (no prior version) is unconstrained.
OE1277ErrorLiveRegistryCacheCoordinateMismatchA cached registry package’s extracted [package] manifest does not match the registry coordinate the resolver selected: its name/version differs from the (name, version) the index resolved and the content hash was verified against. A cached directory is folded into the build like a path dependency, so a mismatch means the cache entry holds the WRONG package (cache poisoning, a content-hash collision, or a stale/corrupt extraction) — admitting it would silently compile a different package than the one resolution chose. The dependency is refused naming both coordinates rather than trusted blindly. Clear the package cache under ~/.argon/packages and re-resolve.
OE1278ErrorLiveRegistryInvalidChecksumA registry index cksum is not a valid content-hash. The cksum is the BLAKE3 content-address of a version’s artifact and is used VERBATIM as a filesystem path segment — the blob download location resolved from the dl template (typically blobs/<cksum> under ~/.argon) and the content-addressed cache directory name — so it must be a non-empty hex string ([0-9a-fA-F]+): no path separators, no ./.. components, no empty string. A cksum like ../../../../etc/hosts would otherwise escape the blob store and be opened, read, and hashed BEFORE the content-hash integrity check runs — an arbitrary-file-read / existence-oracle primitive on a hostile or MITM’d index (registry integrity rests on TLS until index signing lands in a future release). It is validated at the index parse boundary and re-checked before the blob location is built, and refused loudly rather than silently traversing. The index record is bad; if it persists the registry object is compromised.
OE1279ErrorLiveBuildEventIdSpaceExhaustedThe build minted more axiom events than the 20-bit per-build EventId sequence band holds (1,048,575): the workspace lowers more declarations, facts, and metaproperties than one .oxbin’s event-id space can name. The per-build counter deliberately spans the stdlib and every workspace file in one pass (EventId monotonicity across the composed event stream), so this is a whole-workspace ceiling, not a per-file one. Before this code the mint SATURATED at the ceiling — every subsequent event received the SAME clamped id, so the emitted artifact carried silently aliased EventIds (deterministically, on every rebuild): axiom histories merged, retraction lineage pointed at the wrong event, and the corruption persisted in the .oxbin itself. The build is fail-closed: it now refuses to emit the artifact instead. The ceiling is the MVP event-id layout (build mode packs tx_seconds=0, shard=0, leaving the 20-bit sequence); a wider band via the shard or tx_seconds fields is future work. Split the package into smaller modules built as separate artifacts, or move bulk fact data out of source into a runtime ingest path.
OI1207InfoLiveProjectionCacheSkippedox build did NOT embed the section-6 projection cache (the persisted derived read-model) in the emitted .oxbin, and this note names why. The build-time cache is default-on but declines — honestly, with this diagnostic rather than a silent gap — any module outside the v1 fragment: (1) a DATED module (a fact or rule carries a bounded valid-time window, pub fact … at #date# — the model changes when the wall clock crosses a validity epoch with no storage change, and v1 does not persist epochs); (2) a CLOCK-READING module (a rule body — ordinary or enumerate-derive — reads the evaluation clock via today(): a day-N model read on day N+1 would serve stale clock-derived tuples that no content commitment can see); (3) a METRIC-TEMPORAL program (box_minus/box_plus/diamond_minus/diamond_plus/since/until atoms, enumerate-derive bodies included — the catalog wire form drops per-tuple temporal intervals, so a temporal model cannot round-trip); or (4) an encoded payload over the v1 cap (min(64 MiB, 4 x events-section bytes)). A skipped artifact is byte-compatible and behaves exactly as before this feature: every consumer re-saturates from the event log on first read (the cost is one fixpoint per cold process, not wrong answers). Each exclusion is a named predicate with a named upgrade path, not an implicit gap. --no-derived-cache skips emission silently by request. The emitter is the in-process build pipeline (oxc-workspace), so ox build, ox test’s test build, and every embedder render it.
OI1208InfoLiveProjectionCacheServedA read session was answered from the artifact’s section-6 projection cache (the persisted derived read-model): the consumer arm passed every gate (provenance admitted, pristine-seeded store, registry-free, in-fragment, tzdb/format/commitment/generation verified), decoded the payload, restamped the world-assumption map and metric resolution from the module, and served the model without running the fixpoint. This note is the OBSERVABLE half of the projection-cache conformance gate: the golden-anchored corpus entries (conformance/corpus/projection_cache_roundtrip) require it INDEPENDENTLY in ox test and ox run-scenario output, so either command silently falling back to recompute fails the gate rather than passing on correct-but-recomputed answers. Rendered once per session (per scenario store; once per ox test run when any per-test store seeded) by the two commands the conformance gate drives — it is a cache-route marker, not a warning: answers are identical either way (the differential oracle pins seeded ≡ recomputed). Its dual is the ProjectionCacheIgnored warning, which fires when a PRESENT section is refused as invalid; this info note marks when one is actually served. (This rendered text deliberately names the sibling by name, never by code: the help body prints on every marker, and a literal sibling code here would false-positive every grep-for-the-warning-code check over combined output.)
OW1206WarningLiveProjectionCacheIgnoredA .oxbin projection-cache section (id 6) is present but INVALID, so it is ignored and the read re-saturates from the event log. Refusal causes: the derivation commitment does not match the consumer’s own recomputation, the seed generation tuple does not match the pristine-seeded store, the section’s directory content hash does not verify against the body, the payload is undecodable or over the decode bounds (the 64 MiB / events-derived cap, or a declared-count/length bomb caught by the structural preflight), its payload_version / derivation semantic epoch is outside what this consumer reads, its fragment_v1 assertions disagree with the consumer’s own re-derivation (or the module is outside the v1 fragment), or a zone-aware program’s pinned tzdb does not equal the consumer’s bundle. An invalid cache is NEVER served — the arm fails closed to a full recompute, so answers stay correct; this warning exists so a corrupt, tampered, or stale cache is a visible event rather than a silent per-read performance cliff. An ABSENT section is the normal cold shape and falls through silently (the book’s ‘runtime re-saturates if absent’); only a present-but-refused, consumption-admitted section warns this code — a store-shape decline (a non-pristine or registry-bearing store, a non-default scope, or the user’s own --no-derived-cache) stays silent, and an untrusted FOREIGN artifact’s present section warns its own trust-refusal code instead, before any validity gate runs. Rebuild the artifact (ox build) to refresh the cache, or pass --no-derived-cache to disable cache consumption entirely. The emitter is the strict-read consumer arm (ensure_strict_cache); the CLI consumers (ox query / derive / run-scenario) render it once per session.
OW1209WarningLiveProjectionCacheForeignIgnoredA loaded .oxbin carries a projection-cache section (id 6), but the artifact is FOREIGN — not built by this invocation and not recorded in this user’s trusted-artifacts ledger — so the cache is ignored and the read recomputes from the event log. Answers stay correct; this warning makes the trust refusal a visible event rather than a silent per-read performance cliff. WHY the gate exists: a cache section moves the artifact’s trust surface from auditable inputs (events — checkable by replay) to unauditable conclusions — a planted cache can serve rows the rules never derived, and nothing recomputes to notice — so consumption defaults to self-built artifacts only, established mechanically (ox build appends the whole-file BLAKE3 hash of every artifact it writes to the per-user ledger: $ARGON_TRUSTED_ARTIFACTS, else $XDG_STATE_HOME/argon/trusted-artifacts, else $HOME/.local/state/argon/trusted-artifacts), never by path shape. To proceed deliberately: rebuild the artifact yourself (ox build), pass --derived-cache to trust it for one load, set trust-derived-cache = true under [cache] in the per-user config file to trust standing, or run ox verify-cache to recompute the model and diff it against the embedded cache before trusting. --no-derived-cache disables consumption silently by request. This code also names a VOIDED environment-directed trust grant: when the trusted-artifacts ledger or the per-user config file resolves INSIDE the current workspace root (repository-shipped env machinery — a direnv .envrc, a Makefile, a .cargo/config.toml [env] table — pointing ARGON_TRUSTED_ARTIFACTS / XDG_STATE_HOME / ARGON_CONFIG / XDG_CONFIG_HOME at repository-controlled files), the grant is void — a repository must not vouch for its own artifacts — the artifact classifies foreign (or the standing config grant is ignored, the rest of the config still applying), and the warning names the resolved path and the workspace root. The emitter is the strict-read consumer arm; the CLI consumers (ox query / derive / test / run-scenario) render it once per session. Its sibling warning fires when a TRUSTED cache is present but invalid (corrupt, tampered, stale); this one fires before any validity gate — an untrusted section’s bytes are never even decoded.
OW1240WarningLiveUnusedManifestKeyAn ox.toml section or key is not recognized by the compiler (Cargo-style “unused manifest key”). Recognized surface is [package]/[project]/[schema]/[dependencies]/[lattice]/[standpoints]/[store]/[placement]/[workspace]/[patch]/[registry]/[fmt]/[lints]/[temporal] and their known keys; anything else (a typo, a not-yet-supported section, an unknown [lattice].max_tier ladder name) is surfaced as a warning naming the section/key rather than silently dropped by deserialization.
OW1241WarningLiveUnknownLintA lint name in a #[allow/warn/deny(...)] attribute or the ox.toml [lints] table is not a registered lint. A lint name keys a level-controllable diagnostic (e.g. non-canonical-clause-order for OW0010); an unknown name is surfaced — with a did-you-mean suggestion when one is close — rather than silently ignored, because a typo’d name would leave the diagnostic at its default level with no signal. The level value itself (allow/warn/deny) is also checked: a [lints] entry whose value is not one of those words is reported here too. The configured lint set is OxcDiagnosticCode::ALL_LINTS.

Runtime contract and rule-evaluation gates (13xx, §17)

ox build is fail-closed: it re-runs the runtime’s own rule compiler as an oracle over every rule and refuses to write an .oxbin if any rule will not evaluate. The aggregate/quantifier codes (OE1311–OE1315) are the gate’s refusals.

CodeSeverityStatusNameMeaning
OE1301ErrorReservedUnsafeLogicTimeoutQuery touching an unsafe logic { } rule exceeded the runtime’s wall-clock budget (§17.5).
OE1302ErrorLiveFederationDisagreementA federated query under #[federate(strict)] produced a row whose AFT info-join across contributing standpoints is Truth4::Both — at least one source asserts Is, at least one asserts Not. The K3 fail-closed projection at the query boundary rejects the disagreement. Switch to the default paraconsistent policy to receive the row tagged as Both, or reconcile the contributing standpoints’ axioms (§11.2).
OE1303ErrorLiveRuleNotRangeRestrictedA reasoner rule is not range-restricted (unsafe): a variable in the head, inside a negated (NAF) atom, or as a comparison/compute operand is never bound by a positive body atom. Such a rule degrades silently — an unbound head variable projects Null, an unbound negated/compared variable mis-evaluates — so it is refused at compile. Bind the variable with a positive body atom (standard Datalog range-restriction / safety). The named offenders are genuine VARIABLES: every multi-segment path in a value position is resolved (enum constant / axis value / type reference / declared individual) or refused (OE0227 / OE0620) at elaboration, so a qualified path like rigidity::anti_rigid can no longer reach this error — an offender containing :: indicates an artifact built by a pre-S0 toolchain; rebuild from source.
OE1304ErrorLiveNonComparisonOperatorA reasoner Comparison atom uses a non-comparison operator. Only == / != / < / <= / > / >= are meaningful as a rule-body filter; any other operator (e.g. +) makes the executor’s ordering test undefined and would silently drop every row, so it is refused at compile.
OE1305ErrorLiveTierNotYetImplementedRule classified at a tier the current runtime executor does not yet support.
OE1306ErrorLiveRuleExceedsExecutorTierRule’s classified tier exceeds the dispatched executor’s supported_tiers upper bound.
OE1307ErrorLiveComptimeNotStaticRule declared #[comptime] depends on runtime state (mutation, dynamic individual, or non-static relation).
OE1308ErrorLiveComptimeForbiddenOnMutate#[comptime] is not admissible on mutate declarations.
OE1309ErrorLiveStratificationNafCycleNAF dependency cycle prevents stratified evaluation; use SLG (expressive tier) or rewrite.
OE1310ErrorLiveSemiringMismatchProvenance witnesses combined under incompatible semirings.
OE1311ErrorLiveNestedAggregateNested aggregates (count { count { ... } > N }) require answer-subsumption (SLG-class) evaluation and are refused in v0.1. Flatten via an intermediate pub derive rule, or wait for the V1 SLG kernel.
OE1312ErrorLiveAggregateKindNotImplementedCollection/string aggregate kind not yet implemented. The folding kinds (count / count_distinct / sum / min / max / avg) evaluate at runtime today; collect / set_collect / string_join / percentile require the V1 SLG kernel (Expressive tier). The collection-kind subquery forms — collect { … } (List), set { … } (Set), one { … } (Option) — are refused under this code too: pre-refusal they silently lowered to count (a green-checked cardinality test instead of the documented collection semantics). Use count { … } / exists { … }, or an intermediate pub derive.
OE1313ErrorLiveNafAggregateForbiddenNegation-as-failure (not) cannot wrap an aggregate subquery (count { … }, exists { … }) in v0.1 — the result is unsound (the inner aggregate was silently dropped by lowering, pre-γ.7). Rewrite via an intermediate pub derive rule that exposes the aggregate result, then negate over it: pub derive any() :- exists { p(x) }; pub derive none() :- not any();. Lift planned alongside the V1 SLG kernel.
OE1314ErrorLiveEmptyAggregateBodyEmpty aggregate body (count { }, exists { }) is refused — the resulting cardinality is the trivially-vacuous count of the surrounding binding (always 1), which is almost certainly not what the modeler intended. Provide at least one atom in the body, or use a constant predicate.
OE1315ErrorLiveQuantifierNotYetA quantifier rule atom is refused because the executor can’t yet evaluate this shape as a true quantifier (emitting anyway would silently over- or under-derive). The supported universal forall v: T where Body, Head (≥2 where-atoms — the last is the consequent, the rest the domain) DOES evaluate: it lowers to the count-equality count { v: Body, Head } == count { v: Body }. OE1315 fires for the shapes that don’t yet: an exists-FOL binder (exists v: T where …), the paren restriction form (forall(path, T)), or a forall whose where clause has fewer than two atoms (ambiguous domain/consequent split). Rephrase via explicit aggregates or an intermediate pub derive; the count { … } / exists { … } subquery forms are unaffected.
OE1316ErrorLiveTemporalOpUnsupportedAn unsupported temporal operation reached the evaluator and is refused loudly rather than silently mis-evaluated: arithmetic outside date±duration / date−date / duration±duration (e.g. Date + Date, scaling a temporal value, or mixing a temporal value with a number), a chronological comparison across mismatched temporal types (Date vs Duration, or a temporal value vs a non-temporal one), a calendar-relative duration (P1M/P1Y) or sub-day component (PT…), or today()/now() inside a rule. Surfaced identically in the reasoner and the mutate body. The PROVABLE subset is additionally refused at ox check / ox build under this same code: a rule/query-body arithmetic op whose BOTH operand types are statically known (a Date/Duration literal, or a field projection whose base is TypeTest-bound to a concept with a declared Date/Duration field) and fall outside the defined matrix — e.g. e.happened + 30 with a bare numeric literal (fix: a duration literal, 30.days) — refuses before the artifact is written instead of dying at the first evaluation; an operand the build cannot type stays runtime-guarded, never a false positive. Scalar day-granular date/duration arithmetic and chronological comparison are supported; interval and Allen-relation operations live in the std::time/std::allen library over this value layer.
OE1317ErrorLiveRecursionThroughAggregationA predicate’s derivation recurses through an aggregate over itself — an aggregate body (count { … }, exists { … }, or the forall count-equality encoding) references a predicate in the same recursive cycle, e.g. pub derive Fulfilled(c) :- …, forall x where x in c.parts, Fulfilled(x);. Stratified-aggregate semantics (Faber-Pfeifer-Leone 2010) require the aggregated predicate to live in a strictly-lower stratum, so recursion through aggregation has no well-defined fixpoint and is refused at ox check / ox build rather than crashing the runtime evaluator. If the aggregate is incidental to the cycle, break it with an intermediate pub derive that materializes the aggregated predicate in a lower stratum. If the aggregate is a universal over the predicate being defined (a forall / count-equality over child parts — recursion depth is data-dependent, so no intermediate derive can leave the cycle), rephrase it as negation-as-failure double negation: derive a counter-example helper with not P(child) (pub derive HasUnfulfilledChild(p) :- childOf(p, c), not Fulfilled(c);), then P(parent) :- …, not HasUnfulfilledChild(parent); — recursion through negation is evaluated under well-founded semantics.
OE1318ErrorLiveUnsupportedMutationFormA mutate body contains a statement form the runtime cannot yet execute (emit, …). The parser and elaborator admit the form but execution would abort at first invocation, so ox check / ox build refuse the artifact up front instead of shipping a mutation that dies at runtime. Rephrase the statement or wait for the executable form to land. match is executable in BOTH positions: value position (a let RHS, an update … set value, a return/tail value, a require guard, desugared to a Term::IfExpr chain) and statement position (arms running effects, desugared to an Operation::If chain).
OE1319ErrorLiveMatchPatternNotYetA match arm uses a pattern form that does not yet execute: a binding pattern (a bare identifier that does not resolve to a payloadless enum constant), a payload pattern (Some(x), Type { … }), a tuple pattern, an arm guard, a type-test arm, or an is-outcome arm. The executable subset is ordered first-match over CONSTANT patterns: payloadless enum constant paths (Status::Active), Int / String / Bool / Date literals, or-patterns of those (`A
OE1320ErrorLiveConditionalArmFieldNotTotalA rule-body conditional expression (a value if, or a match desugared to one) projects a field inside a conditional ARM that is not total (required) on its holder — the field is declared optional (T?), or no declaration of it is visible. The relational lowering hoists every arm’s projection into an unconditional $field::<f> join, and $field::<f> has no row when an individual lacks the field — so a row missing an optional field would be SILENTLY dropped even when the arm projecting it is never selected. Refused at ox check / ox build rather than mis-evaluated. Workarounds: split the conditional into one rule per arm (each joining only the fields that arm needs), or declare the field required. Projections of required fields inside arms, and projections in always-evaluated positions (the rule body proper, the outermost condition), are unaffected. Lazy presence-guarded branch joins are the tracked long-term fix.
OE1321ErrorLiveEffectInValuePositionA block in VALUE position (a let RHS block, a value-if branch, a value-match arm) contains an effectful mutate statement (update, delete, forget, require, for, emit). Value lowering reduces a block to its tail expression — the statements would not execute, so the effect would silently vanish. Refused at ox check / ox build instead. Use a statement-position if / match (whose branches DO run effects), or hoist the effect out of the value expression.
OE1322ErrorLiveStaticCheckInstanceVocabularyA #[static] check reads instance vocabulary. #[static] asserts compile-time discharge intent, and discharge is staged by what the body reads: a check is catalog-level — evaluated finally at ox check / ox build — iff every head parameter and body variable is catalog-sorted: a reflective sort (TypeRef, TraitRef, or Metatype; declaration structure read through specializes, implements, the type column of iof / meta), or an axis-value type (the element type of a pub metaxis Set/Typed domain, read through the catalog-closed $setAxis / $axis relations with n in meta(t).axis). This check binds at least one variable over individuals (a concept/relation predicate atom, a $field:: projection, or the entity column of iof / meta), so its vocabulary classifies it instance-level and it would silently reclassify to runtime discharge — exactly the drift #[static] exists to catch. Either rephrase the body over catalog-sorted variables only, or drop #[static] to accept instance-level (runtime + declared-EDB-at-build) discharge.
OE1323ErrorLiveMalformedCheckDiagnosticA check rule’s => Diagnostic { … } payload is missing or malformed. Diagnostic is check-surface syntax interpreted by the compiler (like the #[default] defeat-plane directive), not a user type — no import declares it, and its shape is fixed: exactly the fields severity: (the path Severity::Error / Severity::Warning / Severity::Info — nominal, closed set), code: (a string literal), and message: (a string literal, or format!("…{}…", args) with positional {} placeholders matching the argument count one-to-one). code: and message: are always required; severity: is required UNLESS the check is a trait-member impl whose trait pins the member’s severity (check Member(Self) => Severity::…;), in which case omitting severity: inherits the pinned one (a divergent restatement is OE0676); unknown or duplicate fields are refused; at: is reserved for span attribution (the LSP consumes it when it lands) and is refused until then. Named ({name}) or spec’d ({:?}) interpolations are refused — only the empty positional {} form evaluates; a brace placeholder in a plain (non-format!) message literal is also refused, since nothing would interpolate it. Literal braces are written {{ / }} — the escapes work in plain messages and format! templates alike. #[observe] is refused on a non-Error check — Warning / Info checks never guard, so there is nothing to opt out of.
OE1324ErrorLiveCheckCodeNamespaceA check’s code: string does not follow the user-code namespace discipline: the code must be ::-qualified (e.g. "Lease::E001" — a package/domain prefix, then the code), and the OE / OW prefixes are reserved for the compiler’s own catalog (this extends the compiler’s hygiene rule to user space — a user check masquerading as a compiler diagnostic would be indistinguishable in build output and tooling filters). Pick a namespace that names your package or standard ("OntoClean::C1", "HR::W014") and keep the compiler prefixes out of it.
OE1325ErrorLiveCheckMessageArgUnboundA format! argument in a check’s message: does not resolve against the check body’s bindings. Message arguments are evaluated per violation tuple, so every variable they mention (directly, or as the receiver of a field chain like c.cite) must be bound by the rule — a head parameter or a variable bound by a positive body atom — exactly the range-restriction discipline OE1303 enforces for rule heads. An unbound argument has no value at rendering time and would interpolate garbage (or drop the row) silently, so it is refused at ox check / ox build. Bind the variable with a positive body atom, or interpolate a bound one.
OE1326ErrorLiveTraitMemberNotYetA trait or impl body declares a form the compiler cannot elaborate. All five TRAIT member forms land end-to-end: rule-plane members (derive/check/query, slice 1) and invocation-plane members (fn/mutate, slice 3) elaborate, conformance-check, and execute. This gate remains for the genuinely unsupported shapes: trait-side DEFAULT member bodies (V1 bounded-generics territory — a default body cannot typecheck against Self’s fields without structural bounds; the OE0667 family), inherent (bare-impl) members (no trait contract, no dispatch story — a follow-on), and unrecognized member forms (associated const/type bodies, junk items). The member parses and is named in this diagnostic together with its declaring trait or impl; ox check / ox build refuse the program rather than shipping an artifact in which the member silently does not exist (v0.1 previously DISCARDED trait/impl body items without a diagnostic). Remove the member, move the default body into each impl, or declare inherent behavior through a trait impl.
OE1327ErrorLiveTraitMemberUncoveredA bare trait-member atom is called over an argument whose static type (the calling rule’s head-parameter annotation) is not FULLY covered by the trait’s impls. Coverage is a workspace-closed catalog scan: every instantiable declared S ⊑ T must satisfy S ⊑ target for some impl target — instantiable means NOT abstract (the type’s own modifier, or its introducing metatype’s, read from the wire — never a user axis name; the pre-S4 sortality token scrape is retired). The default is instantiable: an unmodified declaration obligates coverage, and the exemption is the explicit abstract opt-in. Under naive clause union an uncovered type would make the atom silently FALSE — the silently-vacuous shape this project refuses. Fixes: add the missing impl(s), declare the never-directly-instantiated supertype abstract, or make the partial dispatch explicit with the conformance guard implements(meta(p), Trait) as a body conjunct — the guard’s $implements join then excludes uncovered individuals visibly. A static type with NO covered instantiable subtype stays refused even with the guard written (the guard would be vacuous; the help says so).
OE1328ErrorLiveDuplicateCheckHeadTwo check declarations in the same module scope share a head name. derive rules union same-head clauses natively (the §7.3.1 disjunction idiom), but that idiom canNOT apply to checks: a check’s head carries payload identity — the => Diagnostic { severity, code, message } report, the guard classification, and the violation relation all belong to the head — so two checks sharing one head would cross-talk (one check’s violations rendered under the other’s severity, code, and message template, with garbage interpolation when the templates differ). Refused at ox check / ox build. Rename one check, or express the disjunction in a single check body (e.g. over a shared derive predicate whose same-head clauses union, then one check reading it). Trait check members are unaffected: each impl’s monomorphized member rule is qualified by its impl target (Trait::Member@Target) and keeps a distinct head.
OE1329ErrorLiveCheckHeadConsumedA rule-body predicate atom resolves to a check head. Check heads are observer-only (§7.1: check never populates the IDB) — a check’s violation set is a report with payload identity (severity / code / message), not a derived relation other rules may join. Consuming it would make derived facts depend on diagnostic machinery (and on whether a check happens to be discharged), the inverse of the architecture. Refused at ox check / ox build for every consuming rule mode (derive, check, query, bridge bodies). Derive from the underlying body predicates instead: factor the check’s violation pattern into a pub derive head, reference THAT from both the check and the consuming rule.
OE1330ErrorLiveTemporalQualifierOnWriteA write statement in a mutate body carries a valid-time qualifier (insert iof(p, T) at <expr>, during <expr>, since <expr>). The parser and elaborator build the qualifier faithfully, but the runtime write path never consumes it — every DML arm destructured it away, so the qualified write applied as if unqualified (the bitemporal extent stamped vt_start = vt_end = None), silently producing atemporal data for a user writing temporal assertions per the book. The storage substrate carries bitemporal extents and as-of reads are exact, but threading user-supplied valid-time through the write path (evaluating the qualifier Term, mapping at/during/since onto vt_start/vt_end, and extending the shared emit_* storage signatures across both backends) is work that is not yet wired. Refused at ox check / ox build rather than dropping the qualifier silently, the same fail-closed discipline as OE1318. Drop the qualifier to write at the current valid time, or wait for the bitemporal mutation forms to land.
OE1331ErrorLiveValueAggregateBraceFormA value aggregate (sum / min / max / avg) was written in brace form sum(expr) { atoms }. Only the cardinality aggregates count { … } / exists { … } take the brace form; a value aggregate uses the comprehension form sum(expr for x in Source, atom, …), whose comma-separated trailing atoms (relation joins, comparisons, type tests) refine the fold’s domain and whose grouping is the outer bound variables. Rewrite sum(e.amount) { posted(e, acct) } as sum(e.amount for e in Entry, posted(e, acct)). Refused at ox check / ox build rather than silently mis-folding — one spelling per aggregate role (the house single-spelling rule).
OE1332ErrorLiveAggregateOverUndefinedAn aggregate folds over a relation that carries well-founded-UNDEFINED atoms ($undefined::R is non-empty for an aggregated predicate). Aggregates evaluate over the definitely-true extent; folding when part of the input is neither true nor false would silently treat undefined as false (the undefined-as-false leak) — biasing sum / count low and min / max arbitrarily, with no diagnostic. Refused loudly at runtime instead, the same fail-closed discipline the WFS check boundary uses. The refusal is WHOLE-RELATION, not per-group: any non-empty $undefined::R companion trips it, even when the undefined tuples belong to a group key that the current binding would not fold — a conservative stopgap that never folds undefined-as-false. Three-valued aggregate intervals over the undefined set are the designed follow-up; for now, stratify the aggregated predicate so it has a definite extent (no recursion-through-negation feeding the fold), or aggregate over an intermediate pub derive that is itself definite.
OE1333ErrorLiveRoundingBuiltinArityA rounding builtin (round / round_half_even / trunc) was called with the wrong number of arguments. round(x) rounds to the nearest integer (ties away from zero) and round(x, n) to n decimal places; round_half_even(x, n) rounds to n places with ties to even (banker’s rounding — the money default); trunc(x, n) truncates toward zero at n places. All operate exactly over the numeric tower (Decimal stays Decimal, never via f64). Refused at compile rather than silently dropping the row.
OE1334ErrorLiveBindingLhsNotSimpleVarA body-level binding atom x = expr has a left-hand side that is not a fresh single-segment variable — a dotted projection (x.f = e) or a ::-qualified path (m::x = e). A binding introduces a NEW variable, so its left-hand side must be a bare identifier. = is the binding (assignment) operator in a rule body, distinct from the comparison ==; it is NOT a field-update operator (that is the mutate-body update … set { field = … } statement). Refused at ox check / ox build rather than falling through to a bare-path Boolean atom, which would silently drop the right-hand expression — the loud-or-working discipline (nothing silently dropped).
OE1335ErrorLiveBindingLhsAlreadyBoundA body-level binding atom x = expr names a left-hand side x that is ALREADY bound — by a prior positive predicate atom, a head parameter, a projection, an aggregate result, or an earlier binding. A binding introduces a FRESH variable; reusing a bound name was silently degrading into an equality FILTER (x joined against the computed value) rather than a binding, so two readings of the same = (bind vs. compare) collapsed with no diagnostic. Refused at ox check / ox build: use == to compare x against the expression, or pick a fresh name for the binding. (== filters over already-bound operands; = binds a new one.)
OE1336ErrorLiveBindingInComprehensionA binding atom x = expr (single =) appears as a trailing atom inside an aggregate comprehension (sum(… for v in S, …, x = expr)). Bindings are NOT a comprehension trailing-atom form: the comprehension body admits predicate joins, comparisons, type tests, and membership — filters that refine the fold’s domain — but a binding introduces a fresh variable whose safety the aggregate sub-scope does not check, so it is refused rather than admitted half-checked. Two rewrites cover every use: project the value directly into the fold (sum(u.v for u in T, rel(t, u)) instead of sum(w for u in T, rel(t, u), w = u.v)), or bind in the OUTER rule body and aggregate the bound variable. Refused at ox check / ox build with this directed hint rather than a generic parse error (== to compare is still accepted as a trailing filter).
OE1337ErrorLiveCalendarRelativeDurationA duration literal <int>.<unit> names a CALENDAR-RELATIVE unit (.months / .years) whose length in days depends on the anchor date — 1.months is 28–31 days, 1.years is 365 or 366 — so it has no fixed value in Argon’s day-granular Duration layer. The supported units are .days and .weeks (a fixed day count: <n>.daysn, <n>.weeks7n), which lower at rule-term resolution to a Duration literal that Date ± Duration arithmetic evaluates exactly. Admitting a calendar-relative unit would force a silent, anchor-dependent approximation — refused loudly instead. Use .days / .weeks, or compute the target date explicitly (e.g. an end-of-month date as data).
OE1338ErrorLiveDateIntrinsicArityA date intrinsic (today()) was called with arguments. The date intrinsics are NULLARY — today() reads the current valid-time of the evaluation (the reasoner’s evaluation clock, fixed for the whole fixpoint so a rule stays a pure function of its snapshot) and takes no parameters. A stray argument is refused at ox check / ox build rather than passed through as an un-evaluable application that would later surface as a generic term-shape failure. Write today().
OE1339ErrorLiveTemporalQualifierUnexecutableA mutate-body write’s valid-time qualifier could not be executed. Two cases: (1) during <window> — window-valued valid-time needs an interval value the surface does not yet carry, so it is deferred; use at <date> (valid-from a civil day), which IS executable. (2) the at <date> / since <date> expression did not evaluate to a Date — e.g. a bare arithmetic value where a #YYYY-MM-DD# literal was meant (the #date# silent-Int landmine: a bare 2024-01-01 is integer subtraction, not a date). The valid-time qualifier must evaluate to a Date (a #date# literal or a Date-typed value). Raised at runtime before any event is persisted, so the mutation commits nothing.
OE1340ErrorLiveBareDateArithmeticA bare YYYY-MM-DD in a rule body parses as INTEGER SUBTRACTION (2024-01-012024 - 1 - 1 = 2022), not a calendar date, and was silently accepted — even against a Date-typed position — modeling a date off by two millennia with no diagnostic (the #date# silent-Int landmine). Argon’s calendar-date literal is HASH-DELIMITED: write #YYYY-MM-DD#. The check fires only on the exact date shape — three zero-padded integer literals (4 / 2 / 2 digit widths) whose fields form a valid civil date (year 1000–9999, month 01–12, day 01–31) — so a genuine subtraction of differently-shaped operands is never flagged. Refused at ox check / ox build with a directed hint toward the real literal.
OE1341ErrorLiveRelationCardinalityExceededA mutate-body relation write (insert <rel>(…)) would exceed a relation endpoint’s declared finite max-cardinality (§5). The i-th bracket constrains how many DISTINCT values position i may take for a fixed combination of the OTHER positions — the standard UML association-end multiplicity. So in pub rel ParentOf(parent: Person, child: Person) [0..2] [*], the position-0 bracket [0..2] caps each fixed CHILD at two distinct parents; a third distinct parent for one child refuses atomically (the body commits nothing) under the closed-world default, counted over committed-plus-overlay tuples (read-your-writes). Before this gate the bracket parsed into a token-soup node no lowering read and the cap was silently ignored. Max-caps are the CWA-checkable half of a cardinality bracket; the min-card half is the deferred OW1342. Emitted by the runtime write path; an open upper bound ([lo..*] / [*]) imposes no cap.
OE1342ErrorLiveBodilessDeriveUnboundArgA bodiless pub derive P(...) — a derive head with no :- ... clause — is a GROUND FACT: it seeds P’s extent with the named tuple, and every head argument must therefore be a CONCRETE term (a declared individual in scope, an enum constant, an axis value, or a type reference). The named argument is none of these — it is a free variable, and a bodiless derive has no body to range-restrict it, so the tuple it would seed is undefined. (This is the bodiless-derive analogue of the range-restriction refusal OE1303 for rules WITH a body: there a head variable is bound by a positive body atom; here there is no body, so the argument must be a constant.) Declare the individual (pub fact T(name); classifies name into concept T), or add a :- ... body that binds the variable. To seed ground tuples on a derived predicate, this bodiless form over concrete arguments is the sanctioned idiom — it unions with P’s other derive clauses and rules over the same head; alongside it, declaring pub rel P(...) and asserting pub fact P(...) is equally valid.
OE1343ErrorLiveMalformedCardinalityA relation endpoint cardinality bracket is malformed (§5): the lower bound exceeds the upper ([3..1]), a bound is non-numeric, or the bracket contains junk tokens. Before this the bracket parsed into a token-soup node that no lowering read, so a malformed cardinality was silently dropped along with a well-formed one; now the bracket is interpreted into a structured cardinality and a malformed one is refused at ox check / ox build. Use [n] (exactly n), [lo..hi], [lo..*] (at least lo), or [*] (any).
OE1344ErrorLiveQueryCteNotYetImplementedA query select-body opens a with <name> = select …; common-table-expression (CTE) clause (§7.4) that does not yet execute. The CTE surface is documented but the binding is not wired into the query planner, so accepting one silently would drop the named sub-result and evaluate the outer select against nothing. Refused by name at parse — distinct from a generic typo — until the planner materializes CTE bindings. For now, inline the sub-query’s filter into the outer select … from … where …, or declare an intermediate pub derive and select over it.
OE1345ErrorLiveQueryGraphTraversalNotYetImplementedA query uses a graph-/path-traversal form (§7.4) that does not yet execute: a select shortest path … / select all_shortest path … projection, a select path <name> … path-binding projection, or a `… as mode walk
OE1346ErrorLiveQueryOptionalFromNotYetImplementedA query select-body uses an optional from … clause (§7.4) — the left-outer-join form that admits rows whose optional pattern has no match (binding its variables to null) — which does not yet execute. The clause is documented but the planner has no outer-join operator, so accepting one silently would drop exactly the rows it is meant to keep. Refused by name at parse until the outer-join lands. Split into two queries, or model the optional fact with an explicit Option-typed field, for now.
OE1347ErrorLiveQuerySetOpNotYetImplementedA query combines two select-bodies with a result-table set operator — union, union all, intersect, or except (§7.4) — that does not yet execute. The operators lex and the surface is documented, but the planner has no set-combination stage, so accepting one silently would return only the first select’s rows. Refused by name at parse rather than a generic token error. Combine the branches with multiple pub derive clauses sharing one head (union), or filter explicitly (intersect/except), for now.
OE1348ErrorLiveRuleRoleStepClosureNotYetImplementedA rule body uses a role-step transitive-closure navigation — x.Role+(y: T) (one-or-more steps) or x.Role*(y: T) (zero-or-more) (§7.3.1) — that does not yet execute. The closure surface is documented (the headline ontology path-traversal form) but the reasoner has no closure operator on a role step, so the +/* after a navigation parsed as stray arithmetic and died generic. Refused by name at parse until role-step closure lands. Write the closure as an explicit recursive pub derive reaches(x, y) :- x.Role(y); reaches(x, y) :- x.Role(z), reaches(z, y); for now.
OE1349ErrorLiveRuleOutcomeSuffixNotYetImplementedA rule-body predicate atom carries a multi-valued reasoning-outcome suffix — is both(a, b), is ambiguous(a), or is timeout(a) (§7.3.1 / §14) — that does not yet execute: both is paraconsistent over-determination and ambiguous / timeout are resolution states, all of which need the richer §14 reasoning-outcome surface. Before this, is ambiguous(a) / is timeout(a) parsed and were SILENTLY DISCARDED (lowered to the bare predicate, dropping the outcome) and is both(a, b) died on a generic parse error — both now refuse by name. The distinct well-founded truth qualifier R(arguments) is unknown is executable for a predicate in a completed lower component; it does not implement these richer outcomes.
OE1350ErrorLiveRuleEverShortcutNeedsDisjunctionThe ever <atom> metric-temporal shortcut (§7.3.2) expands to a DISJUNCTION — diamond_minus[0, ∞](atom) ∨ diamond_plus[0, ∞](atom) (φ held at some past OR some future point) — which the rule-declaration lowering cannot emit, because a single surface rule lowers to a single conjunctive body (no rule-splitting at this layer). The other metric operators lower directly: the four prefix box/diamond forms and since/until are conjunctive atoms, and always <atom> expands to the CONJUNCTION box_minus[0, ∞](atom), box_plus[0, ∞](atom) in one body. Write the two diamond rules explicitly — one head :- diamond_minus[0, ∞](atom) and one :- diamond_plus[0, ∞](atom) — to express the disjunction. (Once rule-splitting lands, ever will desugar to those two rules automatically.)
OE1351ErrorLiveUnsafeLogicBlockNotYetImplementedAn unsafe logic { … } block (§9.3) — the escape hatch that admits a full first-order-logic formula above the decidable tier ladder, opting out of the tier classifier’s termination guarantee — does not yet execute. The surface is documented for the fol tier but no FOL solver is wired in, so the block had no item production and died at module level with a generic parse error. Refused by name until the FOL escape hatch lands. Stay within the decidable tiers (structuralrecursive) for now.
OE1352ErrorLiveMutateUpsertNotYetImplementedA mutate body uses an upsert statement (§8) — insert-or-update keyed on identity, with optional on insert { … } on update { … } arms — that does not yet execute. The keyword is reserved and the surface is documented, but the write path has no upsert effect, so upsert had no statement production and fell through to a generic expression parse error. Refused by name at parse until upsert lands. Branch explicitly on existence with require + a conditional insert / update for now.
OE1353ErrorLiveMutateDetachDeleteNotYetImplementedA mutate body uses a detach delete <rel>(…) statement (§8) — delete a relation tuple and the individuals it solely connects — that does not yet execute. The detach keyword is reserved and the surface is documented, but the write path has no detaching-delete effect (only a plain delete tuple/iof), so detach had no statement production and died on a generic parse error. Refused by name at parse until detach-delete lands. Use a plain delete <rel>(…) and delete any orphaned individuals explicitly for now.
OE1354ErrorLiveAsyncFnNotYetImplementedA function is declared async (or uses .await) (Appendix B) — asynchronous evaluation — which does not yet execute. The async / await keywords are reserved against a future effect system but there is no async runtime, so async fn had no declaration production and fell through to a generic module-level parse error. Refused by name at parse until async lands. Declare a plain pub fn for now.
OE1355ErrorLiveConstDeclNotYetImplementedA top-level const <NAME>: <T> = <expr>; declaration (§19) does not yet execute. The form parsed but SILENTLY SWALLOWED its initializer — it emitted no event and bound no value, so a model could reference a constant that did not exist with no diagnostic (contradicting the no-hollow-features rule and STATUS’s every surface decl lowers to events). Refused by name at parse, rather than silently accepted, until const evaluation and the compile-time-constant plane land. Inline the literal at each use site, or model it as a field default, for now.
OE1356ErrorLiveSinkDeclNotYetImplementedA pub sink <name> { … } declaration carries a brace body, but a sink has no body: it declares a name and the type of value it accepts (pub sink <name>: <Type>;), nothing more. WHERE a sink’s values are delivered — log file, webhook, message queue, HITL ticket — is runtime configuration (the egress dual of read-side placement), never in-language source, so there is no body form to fill in (this is by design, not a pending feature). The braces used to be SILENTLY SWALLOWED via balanced-token skipping — no event, no validation, arbitrary garbage accepted with no diagnostic (a no-hollow-features violation); the declaration now refuses by name. The one sink form pub sink <name>: <Type>; is unaffected, and emit targeting a sink refuses with OE1318 until sink publication has a runtime.
OE1357ErrorLiveRuleNegatedSomePayloadBindingUnsupportedA rule body negates an Option/T? payload binding — path is not Some(<ident>). The positive form is Some(a) binds a to the payload and the conjunction fails on None; under negation there is no payload to bind (the binder would range over nothing), so a bound is not Some(a) is incoherent. The intended meaning is the absence test, written path is None (true iff the field is absent) — refused by name rather than binding a meaningless variable. Use path is None for the negative test, or path is Some(a), not <p>(a) to negate a property of the payload.
OE1358ErrorLiveRuleOptionTestNotFieldProjectionAn Option/T? membership test is Some(a) / is None has a left side that is not a field projection. The test reads an OPTIONAL FIELD’s presence — a present field materializes one $field::<f>(holder, value) row, an absent one materializes none — so its left side must be a field access (p.age is Some(a)), not a bare variable or an expression with no relationalizable receiver. Refused by name rather than silently dropping the option test. Write <holder>.<field> is Some(a) / <holder>.<field> is None.
OE1359ErrorLiveRelationIrreflexivityViolatedA relation declared #[irreflexive] (a generic relation-algebra property — no element relates to itself, OWL IrreflexiveObjectProperty) has a self-loop R(x, x) in its extent. #[irreflexive] synthesizes a check rule over the declared relation’s own extent that fires on any tuple whose two positions are equal; this is that check firing. Either the offending self-pair must not be asserted, or the relation is not actually irreflexive and the directive should be removed. (The directive enforces the relation’s OWN extent — propagation to relations classified-by an irreflexive metarel is a recorded follow-up, not yet enforced.)
OE1360ErrorLiveRelationAsymmetryViolatedA relation declared #[asymmetric] (a generic relation-algebra property — R(x, y) forbids R(y, x), OWL AsymmetricObjectProperty) contains a mutual pair: both R(x, y) and R(y, x) are in its extent. #[asymmetric] synthesizes a check rule over the declared relation’s own extent that fires when a tuple and its converse both hold; this is that check firing. Either one direction of the mutual pair must not be asserted, or the relation is not actually asymmetric and the directive should be removed. Note asymmetry implies irreflexivity (a self-loop is its own converse), so #[asymmetric] alone already forbids R(x, x).
OE1361ErrorLiveRelationFunctionalityViolatedA relation declared #[functional] (a generic relation-algebra property — each source maps to at most one target, OWL FunctionalObjectProperty) has a source related to two distinct targets. #[functional] now emits a blocking check — a definition-site __{rel}_functional head that fires on R(x, y), R(x, z), y != z — refusing a source mapped to two distinct targets. This is the same check-based enforcement as #[irreflexive] (OE1359) and #[asymmetric] (OE1360), and the same check the metarel arm has always emitted; both the rel and metarel arms of the procmacro paste it. This code names the functional-property origin of the refusal so the modeler sees that a #[functional] directive, not a hand-written constraint, is what fired. Either one of the conflicting targets must not be asserted, or the relation is not actually functional and the directive should be removed.
OE1362ErrorReservedRelationPropertyNotImportedRetired — no longer emitted. #[functional] re-homed from a #[builtin] stub to a genuine procedural macro in std::rel (both its rel and metarel arms re-emit the decorated declaration and paste a guarding source-maps-two-targets check, OE1361). It is no longer a registered directive, so an unimported #[functional] — like its siblings #[transitive]/#[irreflexive]/#[asymmetric] — is now refused as OE0705 (unknown attribute macro). This code is retained for historical numbering.
OE1363ErrorLiveMutationCallCycleThe mutation call graph contains a cycle — a mutate body invokes another mutation (directly, mutually, or itself) along a path that returns to its start (§7.5). A sub-mutation call is closed-nested: it runs the callee’s operations into the CALLER’s transactional buffer rather than evaluating to a fixpoint, so the whole transitive call tree is one atomic transaction that commits or aborts wholesale. A recursive cycle therefore has no terminating composed evaluation in v1 — it would unbound-recurse the runtime — so the call graph is required to be statically acyclic and the cycle is refused at ox check / ox build, naming the trail, rather than shipping a mutation that overflows the stack on first invocation (the same fail-closed discipline as OE1318). A trait-member callable edges to every impl body in its group (dispatch picks one at runtime, but any is statically reachable). Break the cycle; recursive mutation composition (fixpoint-to-quiescence) is a separately gated future feature.
OE1364ErrorLiveUnknownTermInBodyA derive / query / check / fn body contains an expression the elaborator could not lower — it degraded to the <unknown> lowering sentinel (Term::Var { name: "<unknown>" }), the fallback an un-lowerable expression form falls back to during expr/atom lowering. The sentinel resolves to no binding at runtime and surfaces as a generic “unbound variable” the first time the body is evaluated, so a body reaching a built artifact carrying one is a silent landmine (this is the same bug-class OE1318 closes for mutate bodies — the self-in-expression-position case — extended to every rule-plane and compute body). The sentinel is refused at ox check / ox build, naming the offending declaration, rather than shipping a rule/query/check/fn that dies generically on its first evaluation. Rephrase the offending expression into a supported form.
OE1365ErrorLiveNegatedWfsRelationA derive rule negates (not R(..)) a relation R that is evaluated under well-founded semantics in a DIFFERENT stratum — a relation whose extent can carry well-founded-UNDEFINED atoms because recursion-through-negation left part of it neither true nor false. The well-founded SCC materializes 2-valued at its boundary: only the definitely-true extent lands in R; the undefined tuples live in the $undefined::R companion relation. Ordinary derive-rule NAF reads only R, so a higher stratum’s not R(x) for a genuinely-UNDEFINED R(x) would read it as definitely-FALSE and over-assert the head — an unsound over-derivation with no diagnostic. Refused LOUDLY at ox check / ox build rather than silently evaluating undefined-as-false, the same fail-closed discipline OE1332 uses for aggregates over an undefined relation (the check boundary already excludes $undefined::R correctly via its K3 firing rule; derive heads do not yet). This refuses ONLY the genuinely-unsound case — a NAF edge whose target SCC is well-founded and is NOT the negating rule’s own SCC; ordinary stratified NAF over a fully 2-valued relation (no recursion-through-negation) is unaffected, and a same-SCC NAF is the recursion-through-negation the well-founded evaluator handles internally. Collapse the negation into the well-founded SCC: instead of splitting into a lower R stratum and a higher H :- .., not R(..) stratum, route H’s recursion through its OWN negation so {H, R} form a single NAF-cyclic SCC the engine evaluates by well-founded semantics directly (the documented win-move idiom in examples/robot_plan_execution/robot.ar ~115-140). Three-valued propagation of UNDEFINED into derive heads (the AFT pair-encoding) is tracked separately.
OE1366ErrorLiveCheckViolationA user-authored check rule fired at Severity::Error (static discharge). The check’s body matched over the package’s catalog / declared EDB, so the obligation it encodes is violated. This is the typed-channel carrier the language server uses to surface a fired check in-editor: the violation’s own namespaced code (e.g. Lease::E001) and its rendered message lead the diagnostic message, since a user check’s identity is the author’s ::-qualified string, not a compiler catalog code. ox check / ox build report the same violation through the user-diagnostic channel and fail the command (the loud-gate); #[observe] opts an Error check out of blocking, and Warning / Info checks render and pass — neither is carried through this code.
OE1367ErrorLiveNegatedOpenWorldDerivedA rule negates (not H(..)) a relation H whose extent can carry OPEN-WORLD-UNDEFINED atoms — H is (transitively) derived through a negation over an open-world (#[world(open)] / default_world = "open") relation, yet H itself is read closed-world. An open-world not C(x) over an absent C(x) is can (unknown), not a definite not, so H’s definitely-true extent omits those can rows; a 2-valued not H(x) then reads such a can row as definitely-FALSE and over-asserts the head — an unsound over-derivation with no diagnostic. Refused LOUDLY at ox check / ox build rather than silently evaluating open-world-undefined-as-false — the open-world analog of OE1365 (the well-founded case), the same fail-closed discipline. This refuses ONLY the genuinely-unsound case: a closed-world not H over a relation whose derivation depends on an open-world negation. To resolve: mark H’s concept #[world(open)] too (so not H reads open-world and tolerates the can), or restructure so the open-world negation does not flow into a closed-world-negated head. Full three-valued propagation of open-world-undefined into derive heads (the AFT pair-encoding) is tracked uniformly with the well-founded case.
OE1368ErrorLiveEmitReservedDiagnosticsSinkAn emit targets the reserved Diagnostics sink. Diagnostics is the language’s built-in diagnostic stream, and a check rule is its SOLE producer — it is fed only through the check => Diagnostic { severity:, code:, message: } consequence, never by a hand-written emit. A direct emit Diagnostics { … } (in a mutate/fn body) or a check => emit Diagnostics { … } consequence is refused by name: the diagnostic channel’s structured shape (severity, namespaced code, per-violation message, the K3 definite-firing discipline) is the compiler’s, not an arbitrary egress payload, so routing a raw value through it would bypass every diagnostic invariant. Emit to a sink you declare (pub sink <name>: <Type>;) for ordinary egress, or use a check’s => Diagnostic { … } consequence to contribute a diagnostic.
OE1369ErrorLiveAggregateCardinalityOverflowA count / count_distinct aggregate’s cardinality exceeds the Int value domain (it does not fit a signed 64-bit integer). The factorized aggregate path computes a count as the EXACT product of its independent factor groups’ sizes — a body of k independent two-row factors yields a count of 2^k — and the value domain’s Int is signed 64-bit, so a count of 2^63 or more has no faithful Int representation. Historically the count was accumulated in usize with a saturating multiply (capping a true ≥2^64 product at usize::MAX) and then cast as i64 (sign-wrapping a ≥2^63 count to a NEGATIVE Int), so the aggregate silently returned a wrong — even negative — count with no diagnostic. The count is now computed exactly and refused loudly when it overflows the value domain rather than emitting a corrupted result. Reduce the aggregated cross-product, or aggregate over a narrower body whose cardinality fits the Int domain; an arbitrary-precision count is a designed follow-up.
OE1370ErrorLiveScalarFromFieldNonFunctionalA scalar navigation-view field (f: T from Rel.endpoint, declared T rather than [T] / T?) is a function: it presupposes the holder backs at most one endpoint tuple, so it can yield a single value (the Lean FieldView rule — a navigation-view field is present iff a backing tuple exists, and stores no value of its own). A scalar from-view is admitted IFF the backing relation is BINARY with a FUNCTIONAL value endpoint (max-cardinality [0..1] / [1..1]). Two refusal reasons fall under this code. (1) BINARY, non-functional value endpoint: the endpoint may back several tuples for one holder, so the scalar view is ill-defined — at runtime it would discard a present tuple. (2) N-ARY relation (arity ≥ 3): a single [0..1] / [1..1] bracket on the value endpoint bounds the value per fixed combination of the OTHER endpoints, NOT per holder, so it is NOT a holder→value functional dependency — e.g. Employment(person, company, salary) [..] [..] [0..1] permits one person two salaries across two employments, which a scalar pay: Int from Employment.salary would silently collapse. (A holder→value functional-dependency analysis that would safely admit some n-ary cases is a documented follow-up, not yet implemented.) The parser admits the declaration but the projection is incoherent, so ox check / ox build refuse it up front. Either declare the field as a collection ([T]) to project the whole endpoint set, or model the dependency with a BINARY relation carrying a functional [0..1] / [1..1] value endpoint.
OE1371ErrorLiveMutateQueryTermNotExecutableA deductive-plane read — a pub query call (applicable(), applicable_for(0)) or a bare derived-predicate (derive) head (Applicable) — appears in a NON-iterand TERM / value position of a mutate body: a let right-hand side (let x = applicable();), a require guard, an update … set value, a constructor field value, or the body tail. A deductive read is SET-VALUED (mutate.md §body-semantics): its sole admissible use in a mutate body is as the iterand of a for x in <query> { … } loop, which binds each projected row in turn and lowers to a reasoner snapshot read over the body’s committed-state plane (§7.5). In a scalar term position it has no value, so it is refused here at ox check / ox build rather than passing the static gates and then dying at the first runtime call with unsupported function … in a term position — the silent-death hole this gate closes. To resolve: iterate the read with for r in applicable() { … } (the documented surface; parameterized reads for r in applicable_for(arg) are admitted and execute), binding each row, instead of reading the whole extent into one scalar slot. A pure compute over a single value belongs in a fn, not a query. The SAME gate refuses a mutate callee in a term position (let x = registerMike();): a mutation is INVOKED as a statement, never read as a value — it is not a term-position callable (nested mutation-as-expression is not a supported form), and before this arm it too passed the static gates and died at the first runtime call. Invoke the mutation as its own statement; a value to compute belongs in a fn.
OE1372ErrorLiveMembershipRhsNotRelationalizableA membership atom member in <rhs> / member not in <rhs> — or a comprehension where … in <rhs> — has a right-hand side the relationalizer cannot lower to membership semantics. The accepted RHS forms are a set/list LITERAL ([1, 2]), a COLLECTION or CONCEPT-EXTENT source (x in Person, x in p.records), and the reflection extents (extent(T), implementors(Tr)). Any other RHS — a bare scalar, an arithmetic expression, a projection that does not relationalize to a bound receiver — was previously dropped to a vacuous zero-arg predicate that derives NOTHING, so a positive in evaluated to the empty extent and a not in was vacuously true for every row, with no diagnostic. The atom is refused here at ox check / ox build so the membership LOWERS to a real relation join or REFUSES — never silently mis-derives. To resolve: write the RHS as a set/list literal, a collection/extent source, or a reflection extent; for a bounded numeric window use the two-sided comparison (r >= lo, r <= hi). (A lo..hi RANGE RHS refuses earlier at parse with OE0001 on ...)
OE1373ErrorLiveIntegerLiteralOutOfRangeAn integer literal — in a pub fact argument (pub fact amount(a, 9223372036854775808)), in a rule / check / refinement body (a comparison constant n == 9223372036854775808, a binding right-hand side, an in set element), or as an as_of <int> transaction-time pin on a query (declared or ad-hoc-submitted, where the pre-fix silent drop read as if no pin were declared) — exceeds the range the implementation’s integer carrier can hold, or is a malformed integer token. Argon’s Int is ARBITRARY-PRECISION at the language level (the exact-numeric tower Nat <: Int <: Real), so the literal is WELL-TYPED; the current compiler simply cannot represent it in the 64-bit (i64) carrier its build artifact and reasoner use — the supported range is -9223372036854775807..=9223372036854775807 (the lower bound is i64::MIN + 1, not the carrier’s true i64::MIN: unary - is a separate token, so -9223372036854775808 is parsed as the positive magnitude 9223372036854775808 first and overflows positive i64, so i64::MIN is not currently a reachable literal). Refused loudly at ox check / ox build rather than the prior silent coerce-to-0, which recorded / matched the WRONG value with no diagnostic: a too-large pub fact amount(a, N) stored 0, and a body comparison n == N aliased to n == 0, so a row stored as 0 spuriously matched a guard written for N. This is an honest implementation-limit refusal, not a claim that the literal is illegal — promoting the carrier to arbitrary-precision is a separate principled change. To resolve: use a value within the supported range, or model the quantity differently (e.g. scale the unit) until the wider carrier lands.
OE1374ErrorLiveRoundingScaleOutOfRangeA rounding builtin (round / round_half_even / trunc) was given a decimal-place count n outside the supported scale domain. The scale is 10^-n, so the builtin forms `10^
OE1375ErrorLiveMutateTupleArityMismatchA mutate-body insert R(args) / delete R(args) supplies the wrong number of arguments for relation R’s declared arity. The mutate-body analogue of OE0221 (pub fact) and OE0225 (rule atom), split by context per the OE0220→OE0225 precedent: a pub fact worksAt(alice) against rel worksAt(person, company) is refused (OE0221), so the symmetric insert worksAt(p) in a mutate body must be refused identically. Left ungated, the runtime would commit a malformed n-tuple into the relation’s extent — a 1-tuple where a 2-tuple was declared — and every read of the relation would surface the corrupt shape. Refused at ox check / ox build, before any artifact commits, exactly as the ground-fact gate refuses it. Supply the declared number of arguments for R.
OE1376ErrorLiveNavViewHolderAmbiguousA COLLECTION navigation-view field (field: [T] from Rel.endpoint) over an N-ARY (arity ≥ 3) relation names only the VALUE endpoint; its HOLDER — an individual of the declaring concept — must occupy a DIFFERENT endpoint, resolved by type. The relation must have EXACTLY ONE non-value endpoint whose declared concept is <:-comparable with the declaring concept. Two refusal reasons fall under this code. (1) NO holder endpoint: no non-value endpoint’s type is comparable with the declaring concept, so the holder can never occupy the relation and the view is statically empty — e.g. declaring staff: [Person] from R.person on Company where R(person, widget, n) has no Company-comparable endpoint. (2) AMBIGUOUS holder: two or more non-value endpoints are comparable with the declaring concept, so from Rel.endpoint cannot say which one is the holder — e.g. Pairing(buyer: Company, seller: Company, item: Item) with deals: [Item] from Pairing.item declared on Company (both buyer and seller could be the holder). A BINARY relation’s holder is the sole other endpoint, resolved POSITIONALLY at runtime with no type constraint, so this gate does not apply to it (a holder dual-classified under an unrelated endpoint concept is a legitimate projection); a SCALAR from-view over an n-ary relation is owned by OE1370. The parser admits the declaration but the projection holder is incoherent, so ox check / ox build refuse it up front rather than silently projecting the wrong column at runtime. To resolve: project from a binary relation whose sole other endpoint is the holder, or model the relationship so the holder endpoint is the unique one comparable with the declaring concept.
OE1377ErrorLiveValidTimeOutOfRangeA valid-time qualifier’s #date# / #…Z# instant — an at <#date#> / at <#…Z#> effective-dating stamp on a pub fact or derive rule, or an as_of <#date#> query clause — names a civil day / instant so far from the Unix epoch that its start-of-day nanosecond value overflows the implementation’s i64 valid-/transaction-time axis (which tops out near year 2262 and bottoms out near year 1677). The literal is a WELL-FORMED, in-calendar-range date/instant; the current compiler simply cannot represent its nanosecond position in the 64-bit axis the bitemporal engine and read points use. Refused loudly at ox check / ox build rather than the prior silent saturating_mul, which pinned a pathological far-future/-past date to i64::MAX / i64::MIN with no diagnostic — so a far-future #YYYY-MM-DD# valid-time aliased to the same axis point as any other overflowing date, and a read as_of such a date matched an unrelated point. This is an honest implementation-limit refusal, sibling to OE1373 (out-of-range integer literal), not a claim that the date is illegal; widening the axis carrier is a separate principled change. To resolve: use a valid-time within the representable range (roughly 1678-01-01 .. 2262-04-11).
OE1378ErrorLiveRelationFunctionalCapConflictA relation declared #[functional] (each source maps to at most one target) also declares an explicit cardinality on its TARGET (last) endpoint whose upper bound exceeds one ([0..2], [0..*], [1..*], [*]). The two constraints contradict: #[functional] requires at most one target per source, but the bracket permits more. Rather than silently drop the user’s cardinality or the functional constraint (either would be a silent-wrong), the declaration is refused, naming the relation and the conflicting bracket. An agreeing [0..1] on the target (or no explicit target bracket — the functional check then enforces the bound) is accepted. Remove the conflicting bracket or drop #[functional].
OE1379ErrorLiveRefinementPredicateNotBoolA where/iff refinement predicate — a concept refinement, or the value filter of a navigation-view from clause — has an expression whose inferred type is PROVABLY not Bool (e.g. a bare self.age projection of an Int field, an arithmetic result, a String literal). A refinement predicate decides membership, so its expression must evaluate to Bool; a non-Bool result is unevaluable as a predicate. Before this code such a predicate built cleanly and then failed LOUD at its first evaluation (RefinementUnevaluable at the first extent read, classification, or write-gate check) — a build-accepts/runtime-refuses drift; cause-determines-response puts the refusal at build time, where the fault is. Only a provable non-Bool is refused: a predicate whose type the checker cannot resolve (an Unknown-typed expression, an unresolved field or name) is NOT rejected here — no false positives — and remains guarded by the loud runtime error. Fix it by making the expression a boolean test (self.age >= 18, not self.age).
OE1380ErrorLiveDuplicateDefinitionThe same module defines the same name twice: a second fn with the SAME name and SAME arity as an earlier one, or a second rel re-declaring an earlier relation’s qualified path. Argon has no overloading-by-type: the two definitions are indistinguishable at every call/atom site, so before this code the program built green and the layers silently DISAGREED on the owner — the checker typed call sites against the FIRST definition while the runtime’s bare-name dispatch table (whose remove-on-second-claim dedup exists for CROSS-module collisions, where qualified calls disambiguate) dropped the shared key, so the first runtime call died with an unsupported-function error naming a function the checker had accepted. A duplicate is refused at build, naming both the duplicated path and its earlier definition. Same-name fns in DIFFERENT modules remain legal (a bare call is ambiguous and refused at the call site; qualified calls dispatch normally), and same-name fns with DIFFERENT arities remain the loud-ambiguity case bare-name dispatch already refuses. Rename one definition, or move it to its own module.
OE1381ErrorLiveFirstOrderInstantiationTargetA : T instantiation clause targets a type the same package PROVABLY uses at the individual tier (pub kind Dog : Animal while a query reads a: Animal, a pub fact Animal(x) asserts a member, or a mutate constructs/classifies under Animal). The : T clause declares type×type iof-instantiation: the DECLARING type becomes an INSTANCE of T, so T’s instances are TYPES — populating or reading the SAME T with INDIVIDUALS is tier-mixing, and with near certainty a mis-spelled SUBTYPE declaration. It does NOT subtype: the clause built green, lowered to a catalog-tier iof row, and the declaring type’s individuals silently never appeared in the target’s individual-tier extent (insert Dog {} never reached a query over Animal) — a silent no-op for the intent. Use <: for specialization (pub subkind Dog <: Animal: every dog IS an animal). The refusal is evidence-driven, never intent-guessing: a : T whose target shows NO individual-tier usage is the legit higher-order form (the target’s extent read at the TYPE tier via iof(t, T), a type-valued relation endpoint) and is never refused.
OE1383ErrorLiveUnboundMutateValueNameA bare identifier in a mutate / test body value position — a relation-tuple argument, a constructor / update field value, a let initializer, a require guard, a return, a for / comprehension source — resolves to nothing: it is neither a parameter, a let / loop / match binder in scope, nor a declared pub fact individual. Such a name has no value at runtime — no identity is synthesized for an unbound name — so the mutation would build green and then refuse at its first invocation (unbound variable). It is refused at ox check / ox build instead, so no artifact ships that dies at dispatch (the loud-gate contract). Fix: bind it as a parameter or a let, declare it with pub fact, or correct the typo. A same-named parameter / let SHADOWS a declared individual (a bound local always wins). A name resolving to a pub query / derive head is a DIFFERENT refusal: a set-valued deductive read has no value in a term position and its sole admissible use is a for x in <head> iterand. A name spelling a DECLARED TYPE (concept / trait / metatype / metarel / relation) is not unbound and never reaches this refusal: unshadowed, it lowers to a type-as-value reference — the same lowering rule bodies apply — and a mis-sorted landing of that reference is OE1384, not OE1383.
OE1384ErrorLiveMutateTypeValueEntityPositionA declared type name used as a type-as-value in a mutate / test body write LANDS in a position whose declared sort holds entities/values, not type references — a relation-tuple argument, constructor field, update … set target, or insert … into element whose declared type is not headed by one of the reference sorts TypeRef / Metatype / TraitRef. A declared type name in a value position lowers to a type-as-value reference (the same lowering rule bodies apply), and the reference lands soundly only in a position declared to hold one: committed into an entity slot it would match no read path — equality dispatch keys type references to reference-sorted columns — so the write is refused at ox check / ox build rather than silently persisted. This is the imperative-body analogue of OE0262 (which refuses a type-as-value pinned into a variable-expecting rule-body slot). A relation whose declared signature the elaborator cannot see reads as all-entity-expecting (fail-closed, as OE0262); cross-module field-type chains and binder-laundered references defer to the same-coded runtime write-gate backstop. Fix: bind a value or individual in that position, or declare the position TypeRef (or TypeRef<C> / Metatype / TraitRef) if it should reference a type.
OE1385ErrorLiveMutateIndividualReferencePositionAn INDIVIDUAL is written to a mutate / test body position DECLARED to hold a type-as-value reference — a relation-tuple argument, constructor field, update … set target, or insert … into element whose declared type is headed by one of the reference sorts TypeRef / Metatype / TraitRef. The reverse direction of OE1384: a reference-declared position holds references to DECLARED TYPES (equality dispatch keys such positions to the declared-symbol catalog), so an individual committed there matches no read path — the write is refused rather than silently persisted, and a tuple DELETE with an individual at a reference position is refused rather than silently matching nothing. Refused at ox check / ox build where the individual is statically known (a construct binding), and at the runtime write gate otherwise (a parameter-passed or binder-laundered individual). The wire boundary already refuses this shape (#i… entity references are rejected for TypeRef-sorted parameters at coercion), so the gate closes the in-language write path to match. A position declared Entity / Top admits individuals — this refusal never fires there; a type reference written to such a position remains governed by the forward landing gate (OE1384). The reflective sort names are not reserved: a USER-declared type named TypeRef (or Metatype / TraitRef) types ENTITY positions, decided by resolved identity, so this refusal never fires against a position typed by such a user declaration. Fix: bind a declared type name (or a TypeRef-valued expression) in that position, or declare the position with the entity sort it should hold.
OE1386ErrorLiveRelationSelectorDomainUnprovenA variable is applied like a relation (r(p, c)) but nothing pins which relations it can stand for, so the compiler cannot list the relations to dispatch to. It refuses rather than guess a set or search every relation at runtime. Constrain the variable to a compile-time-known finite set of relations: equality with a relation name (r == Home), the specializes(r, Family) subsumption family, or a rel/arm/meta reflection atom — each proves the complete candidate set.
OE1387ErrorLiveRelationSelectorNonRelationA variable applied like a relation (r(p, c)) is constrained to a value that is provably not a relation (an Int, String, struct value, …), or its constraints combine relation and non-relation values. Constrain the variable to a relation (r == Home, specializes(r, Family)) or drop the constraint pinning it to a non-relation.
OE1388ErrorLiveRelationApplicationArityMismatchA variable applied like a relation is given a number of arguments that no relation it can stand for accepts — either the relations agree on an argument count that differs from the call, or they disagree among themselves. Apply the variable with a number of arguments every candidate relation accepts.
OE1389ErrorLiveRelationApplicationEndpointMismatchAn argument passed to a variable applied like a relation has a type that cannot match the type declared for that position in at least one relation the variable can stand for (e.g. a text string where the declared type is Int). Pass a value whose type matches the declared position type. Only provable conflicts of primitive and category are refused; an unresolved nominal type that could still be classified compatibly is admitted.
OE1390ErrorLiveRelationApplicationInaccessibleA variable applied like a relation can stand for one or more relations that are private to another module and not visible at the application site. The candidate set is built completely before visibility is checked, so silently dropping the private members would change which relations the rule reads. The refusal names the private relations. Make them public where they are declared, or apply the variable only inside the module that declares them.
OE1391ErrorLiveRelationApplicationUnsafeNegationA negated application of a relation-valued variable (not r(p, c)) is unsafe: negation here means “not derivable”, which is only well-defined over values the rule has already enumerated. Every argument and the variable itself must first be bound by a positive (non-negated) condition. Add a positive condition binding the variable and each argument before the not.
OE1392ErrorLiveCallableTemplateUnavailableA rule calls a function whose stored expandable body is missing or explicitly unavailable, so the call cannot be inlined (this happens when the function comes from a compiled artifact too old to carry the body, or the body was recorded as unavailable). The refusal names the function and the recorded reason. Recompile the module that declares the function with the current compiler, or give the function a usable body.
OE1393ErrorLiveRelationApplicationMetadataUnavailableA variable applied like a relation can stand for a relation whose compiled artifact is too old to carry the visibility and parameter-type information this needs. The refusal names the relation rather than guessing that information (a wrong guess would misevaluate). Recompile the module that declares the named relation with the current compiler.
OE1394ErrorLiveMembershipReadInRecursionA rule reads a membership through the reflection surface — a variable type position (iof(x, t)) or the metatype read (meta(x)) — from inside the recursive cycle that decides that membership: the rule’s head shares a strongly-connected component with a concept relation whose extent feeds those reflection relations. The reflection relations are extensional and are re-materialized once, at a stratum boundary above every rule that reads them; that boundary is what makes the read a settled two-valued fact set and keeps negation over it stratification-safe. Inside the cycle there is no such boundary — the read is part of the fixpoint that decides the answer — so the membership is not yet settled when the read evaluates and any answer served would be arbitrary. Serving it from the pre-rebuild snapshot answers empty for a rule-decided concept, and its negation admits every individual, with no diagnostic; that silent-wrong shape is why this is refused instead. The message names the offending rule(s) and the concept relation(s) they cycle with. Fix: ask the concept directly with a constant type position (C(x)), which lowers to the concept atom and evaluates inside the fixpoint, so it may recurse freely; or move the reflection read out of the cycle — derive the cycle’s conclusion first, then read the reflection surface in a rule that does not feed it back.
OE1395ErrorLiveNegatedUndefinedMembershipReadA rule negates a membership read that is served from the extensional reflection relations — a bound type position (iof(x, t)) or the metatype read (meta(x)) — while the membership it asks about is UNDEFINED under the well-founded semantics. A concept whose members are decided by a rule inherits that rule’s truth value, so when the deciding rule’s own definition loops through the negation of that membership, the individuals concerned are neither definitely members nor definitely non-members. The reflection relations carry that third value in a companion relation beside each of them, and a positive reader propagates it, but a negation reads only the definitely-true rows: it would report an undefined membership as a settled non-membership and over-assert its head. The message names the negating rule(s) and the concept(s) whose membership did not settle. Whether a membership settles is a property of the model rather than of the rule text, so this is decided over the converged model, and only the heads whose rows the negation manufactured are refused — the positive read of the same membership in the same program still answers. Fix: break the negative loop in the rule that decides the concept’s members so the membership settles, or drop the negation and read the membership positively, which propagates the third value instead of collapsing it.
OW1342WarningLiveRelationMinCardinalityDeferredA relation endpoint declares a non-zero MINIMUM cardinality (pub rel Married(a: Person, b: Person) [1..1] — every person must be married) that the closed-world write/check channel cannot soundly enforce in v0. Under CWA a build-time refusal would wrongly reject staged construction (relate the entity in a later mutation), and the field-access-time / evaluation-channel emitter that would actively check it is designed but not built in v0 (the same disposition as OE0207’s staged-construction note). The bracket is NOT silently accepted-as-enforced: it is parsed into a structured cardinality, PERSISTED on the wire (RelationDeclBody.cardinalities), the max-cap half IS enforced at the write path (OE1341), and this WARNING is emitted at ox check / ox build (by oxc-driver) naming the relation + position so the modeler knows the minimum is recorded-not-enforced. Full min-card-under-OWA enforcement is a recorded follow-on.
OW1369WarningLiveEmitCheckBuildTimeNotDeliveredAn => emit Sink { … } check FIRED over the package’s declared facts at ox check / ox build, but its egress is delivered only at the RUNTIME mutation boundary — driven by the violation delta (a newly-violating tuple emits Assert, a resolved one Retract), which has no build-time analogue (there is no receipt at build). So the build-time firing produces no emission; this WARNING surfaces it (naming the check and sink) rather than dropping it silently, the same no-silent-drop discipline a diagnostic check follows. It is informational — the check is sound, the emission simply belongs to the write path. To see the egress, exercise the check through a mutation that changes its violation set.
OW1382WarningLiveInstantiationTargetUnprovenA : T instantiation clause targets a declared concept the package shows NO individual-tier usage of (pub kind Dog : Animal with no facts, direct membership reads, or writes over Animal anywhere). The clause declares type×type iof-instantiation — the declaring type becomes an INSTANCE of T, one order above — and does NOT subtype: if Dog : Animal was meant as specialization, Dog’s individuals will silently never appear in Animal’s extent, and a whole taxonomy authored this way flattens without a single error. With no usage evidence the build cannot PROVE the mistake (the same shape is the legit higher-order form whose target extent is read at the type tier), so this is a WARNING, not a refusal: check whether specialization (<: T) was meant. A target the package does use at the individual tier upgrades to the OE1381 refusal (provable tier-mixing). An iof-headed body read is evidence in NEITHER direction: the reflective call iof(a, T), the membership operator x in T, and for x in extent(T) all lower to one identical IR shape, so the build cannot tell a type-tier catalog read from an individual-tier membership read — a PROVING type-tier evidence channel needs the tier tagged at elaboration and is a separate, pending surface. The warning is level-controllable as the lint instantiation-target-unproven (#[allow] on the declaring concept, [lints] in ox.toml, -A/-W/-D, --quiet).

Individual lifecycle and write-path stability gates (14xx)

Continuation of the runtime write-path gates past the exhausted 13xx range: the individual-retraction cascade’s transactional invariants and relation-end stability refusals allocate here.

CodeSeverityStatusNameMeaning
OE1400ErrorLiveRetractedIndividualReintroducedA mutation body re-introduces an individual after a RetractIndividuals operation in the same transaction retracted it — a later re-classification, relation-tuple endpoint, or property write names the retracted identity, so the committed state would hold live events introducing or referencing an individual the same transaction’s retraction gates treated as ended. The cascade released those bindings on the premise the individual was gone; re-introducing it in the same commit falsifies that premise after the fact, so the whole transaction refuses. Split the resurrection into its own transaction (where the immutable-fiber freeze gates it as a replacement assertion), or do not retract the individual.
OE1401ErrorLiveRelationTargetUpdateAn update target: R set { … } annotates its target with a declared relation type. Relation ends are not assignable fields: a relation assertion is an immutable proposition whose endpoint values are never updated in place, and mut on an end authorizes value variation through tuple retract/assert history only. Replace the assignment with the tuple lifecycle — delete R(…) then insert R(…) — which the relation-end mutability gates validate; fires at ox check / ox build on the mutate body, and again at dispatch for a target only the runtime can classify.
OE1402ErrorLiveImmutableRelationEndRetractionA delete R(…) names a live relation tuple with at least one immutable end. Relation ends are lifetime-bound unless declared mut: deleting the tuple would shrink an immutable end’s frozen value set while its dependent context (the individuals at every other position) still survives. Direct tuple deletion is admitted only when every end is mut. To remove an immutable-ended binding, retract its dependent-context individual — the incident tuple then retracts by cascade — or mark the end mut at its declaration if the binding is meant to vary.
OE1403ErrorLiveImmutableRelationEndInsertionAn insert R(…) introduces a NEW value at an immutable end whose fiber (its value set under the fixed complement of the other endpoints) is already initialized. An immutable end’s value set is frozen atomically by the first transaction that asserts the fiber and cannot grow while its dependent context survives; re-asserting an already-active value stays idempotent. Assert every value for the fiber in its initializing transaction, or mark the end mut at its declaration if the value set is meant to vary through assertion history.
OE1404ErrorLiveImmutableRelationEndStrandedContextA RetractIndividuals (or capability-gated forget) would leave an immutable-ended relation binding whose dependent context still survives. For every tuple incident to a retracted individual and every immutable end, at least one individual in that end’s dependent context (the other endpoints) must be in the same retraction set; the check is conjunctive across all immutable ends. Retracting brain cannot leave its dependent person alive, and retracting one spouse cannot leave its marriage alive. Add the stranded dependent-context individuals to the retraction so the incident bindings retract by cascade, or mark the relevant ends mut. An incident shape whose end-mutability cannot be decided is refused here rather than admitted.
OE1405ErrorLiveAmendWithoutCapabilityA mutate body uses amend but the enclosing mutate declaration does not grant #[allow_amend]. amend corrects the belief-time record: it marks a recorded assertion false ab initio (retaining the audit history) and, in the composite amend R(old) => R(new) form, asserts the corrected tuple. Because it rewrites what was believed, the capability must be granted explicitly — annotate the mutate declaration with #[allow_amend], mirroring forget and #[allow_forget]. An ad-hoc body submitted at runtime is never granted the capability.
OE1406ErrorLiveAmendmentTargetNotAssertedAn amend R(…) named a tuple that is live but has no directly-asserted or refuted event to correct — a purely rule-derived conclusion. amend supersedes a recorded belief-time assertion; a conclusion computed from premises has none. You amend premises, not conclusions: correct the asserted premises the tuple was derived from and let dependency maintenance recompute the conclusion. Amending the conclusion directly is refused rather than accepted as a no-op that recomputation would immediately undo.
OE1407ErrorLiveAmendmentBelowMinimumWithdrawing the amended assertion would leave an already-initialized immutable relation-end fiber non-empty but below its declared minimum cardinality. amend corrected an established fiber (one an earlier transaction froze), and the surviving corrected value set is smaller than the end’s declared lower bound. This is distinct from OE1398, which refuses an under-filled first initialization. The minimum is checked on the post-withdrawal fiber, before any corrected re-assert, so the composite amend R(old) => R(new) form refuses here too: the re-assert does not count toward the minimum this gate enforces. The remedies are to withdraw the whole fiber to empty (which is uninitialized, not under-filled), or to not amend below the declared minimum.
OE1408ErrorLiveRetractTargetNotIndividualA retract target must denote an individual — an entity with a retractable identity lifetime. The target given resolves to a collection, a type/concept name, or another non-individual value, which carries no individual identity to cease. retract x; ceases one individual and retract {a, b}; a set of them; to retract every individual of a collection iterate it (for x in xs { retract x; }), and to remove a derived or relational fact use delete. Give a target that denotes an individual value, or switch to the effect that matches the shape you have.
OE1409ErrorLiveAmendCorrectionRelationMismatchA composite amend R(old) => S(new) names a different relation in its correction than in its withdrawal. amend corrects a mis-recorded fact of a relation, withdrawing one tuple and re-asserting a corrected tuple of the SAME relation; it never moves a fact between relations. To change facts across two relations, delete one and insert the other. Give the withdrawal and its correction the same relation.
OE1410ErrorLiveMappedSubsumptionNotYetEvaluableA relation subsumption clause carries a mapping — a renamed or reordered end, a constant pin, or a subsort cast — against a parent whose declared ends are not visible in this file (a cross-module parent relation). Non-identity mappings are evaluated once the parent’s positions are known, but this build cannot resolve the fillers to the cross-module parent’s positions, so it cannot place them under the mapping and refuses rather than recording an under-resolved edge. Declare the parent in this module, or write the clause as a bare identity edge (<: Parent) whose ends need no translation.
OE1411ErrorLiveMappedSubsumptionUnknownParentEndA relation subsumption filler is keyed by the parent end it fills (parentEnd = childEnd), but the named parent end is not one the parent relation declares. The mapping cannot be placed at any parent position, so the declaration is refused. Check the parent end name against the parent relation’s declared ends; every filler’s left-hand name must be a declared parent end.
OE1412ErrorLiveMappedSubsumptionParentEndCoverageA relation subsumption mapping must cover each parent end exactly once. This mapping either fills one parent end with two fillers or leaves a parent end with none, so it is not a total mapping onto the parent and is refused. Write exactly one parentEnd = childEnd filler for every declared parent end.
OE1413ErrorLiveMappedSubsumptionNegativeDualUnsupportedA program declares a relation subsumption edge with a non-identity mapping (a renamed or reordered end, a constant pin, or a subsort cast) AND asserts a refutation (a negative fact) over the parent family, so the read path would have to flow that refutation DOWN from the parent to the mapped child. That downward direction needs the inverse of the mapping, which is not well defined: a constant pin collapses many child tuples onto one parent tuple, so a refuted parent tuple does not name a unique child tuple to refute. The forward direction (a child tuple contributes its mapped image to the parent, and withdrawing the child withdraws the image) is fully supported; only the negative downward dual through a non-identity mapping is refused, pending a decision on its semantics. Use an identity mapping on the refuted edge, or refute the child relation directly rather than the parent family.
OE1414ErrorLiveFamilyQueryMemberFrameArityA generalized specializes(k(memberArgs), Parent(parentArgs)) family query applies the member selector k in its own frame with a number of arguments that does not match the declared arity of a relation k can stand for. For an identity family the member frame and the parent frame have the same width; write the member frame with one argument per declared end of the member relations. Change k(memberArgs) to carry the arity every candidate member accepts, or use the Parent(args) via k sugar, which supplies the member frame for you.
OE1415ErrorLiveFamilyQuerySelectorNotVariableThe member position of a generalized specializes(k(memberArgs), Parent(parentArgs)) family query must be a plain relation-valued variable applied to its own arguments — the witness k the query binds to the answering member. It was written as something else (a wildcard _, a literal, or a relation name in the member slot), so there is no variable to bind the answering member to. Name a fresh variable in the member slot — specializes(k(a, b), Parent(a, b)) — or drop to the Parent(args) via k sugar, which introduces the witness k for you.
OE1416ErrorLiveFamilyQueryMappedMemberUnsupportedA generalized specializes(k(memberArgs), Parent(parentArgs)) family query — the form with an explicit member frame — reached a family member whose subsumption edge is an argument-mapped, non-identity edge (an end pinned to a constant, renamed, reordered, or cast). The explicit member frame is tied positionally to the member’s own ends, so a member whose mapping does not place its ends one-for-one onto the leading parent positions cannot be framed that way. The via sugar — Parent(args) via k — handles every member, mapped included: it presents the parent-frame row through the member’s mapping and binds k to the answering member. Use via for a mapped family, or query an identity family with the generalized form.
OE1417ErrorLiveFamilyQueryNestedFrameTiesUnsupportedA generalized specializes(k(memberArgs), Parent(parentArgs)) family query (or its Parent(args) via k sugar) whose frame carries a filter — a parent-frame constant pin, or a member-frame rename, reorder, or pin — appears nested under negation or a modal / temporal operator. Such a query lowers to a dispatch-helper application plus one filter atom per tied column. A negation over that conjunction would distribute (De Morgan) into not helper and not filter… rather than the intended not (helper and filter…), and a modal / temporal operand holds only a single atom, so the filters would be dropped — either way the query would silently under- or mis-evaluate. The family-query surface therefore supports a pinned / renamed / reordered frame only as a top-level positive atom for now. Lift the family query to the rule-body top level, binding each column to a variable, then apply the negation or modal / temporal operator to those variables; or query an all-variable frame, which carries no filters and nests freely. The nested cases activate once the expansion can carry its filters into a negated or modal context.
OE1418ErrorLiveFamilyQueryParentFrameArityA generalized specializes(k(memberArgs), Parent(parentArgs)) family query (or its Parent(args) via k sugar) writes the parent frame Parent(…) with a number of arguments that does not match the declared arity of the parent relation. This is a fault in the parent position, distinct from a member-selector arity fault: the remedy is to match the parent relation’s declared ends, not to rewrite a member selector. Write the parent frame with one argument per declared end of the parent relation.
OE1419ErrorLiveFamilyQuerySpecializesViaCombinedA via k clause trails an explicit specializes(...) (or iof(...)) reflection atom. The Parent(args) via k sugar is itself a specializes family query, so the two spellings cannot be combined. Before this refusal the via clause was silently dropped and the bare / explicit form — without the witness — was evaluated instead, a different query than written. Write either the explicit form specializes(k(args), Parent(args)) with a member frame, or the sugar Parent(args) via k, which supplies the member frame for you — not both.
OE1420ErrorLiveFamilyQueryParentUnresolvedThe parent position of a specializes family query (or its Parent(args) via k sugar) does not resolve to a single declared relation — an unknown name, or an ambiguous short name matching more than one accessible relation, which the resolver fails closed on. This is a fault in the parent position, distinct from the member-witness refusal: the remedy names the parent relation. Name the parent with a qualified path, or import it so the short name resolves uniquely.
OE1421ErrorLiveMappedSubsumptionUnmappedChildEndA relation subsumption clause maps its child onto a parent but references only some of the child’s declared ends — at least one child end is named by no filler. Dropping a child end inside a subsumption edge is forbidden: two child tuples that differ only at the dropped end would merge into one parent row (the set-merge consequence — a relation’s extent is a set of true propositions, so facts agreeing on every kept end become one row and any aggregate over the parent counts them once), with no declared meaning for the collapse, and the withdrawal cascade relies on the child identity a dropped end would erase. Fix, in fixed order: (1) if the child genuinely belongs to the family, reference every declared child end in the filler list (a rename or a cast source; a child end may be referenced by more than one parent end — a diagonal — but never by none); (2) if a lossy projection is intended, express it as a separate derive rule — a projection view is not family membership. A dedicated explicit projection-marker on a subsumption edge is a reserved design under consideration (an open question in the mapped-relation-subsumption design record) and is not yet a surface form; until then, use a derive rule.
OE1422ErrorLiveMappedSubsumptionPinSortMismatchA relation subsumption clause pins a parent end to a constant individual whose sort does not inhabit that parent end’s declared sort. A constant pin freezes the named individual into the parent position for every mapped row, so the individual must be of the parent end’s sort — the same sort (from its concept-membership fact, e.g. pub fact Currency(USD)) or a subsort of it. An individual of an unrelated sort (a Person pinned into a Currency end) would produce parent rows that violate the parent relation’s own endpoint declaration, and is refused. The gate is fail-open: it fires only when the pinned individual’s sort is known in scope and is provably neither the parent end’s sort nor a subsort — a pin whose sort is not visible here is never falsely rejected. Fix: pin an individual of the parent end’s declared sort (assert its membership, pub fact <ParentSort>(<individual>)), or, if the pinned individual is correct, widen the parent end’s declared sort at the parent relation.
OE1423ErrorLiveMappedSubsumptionCastSortMismatchA relation subsumption clause casts a child end onto a parent end at a sort that does not match the parent relation’s declaration. A subsort cast (parentEnd = childEnd as Sort) presents the child end’s narrower-sorted values at the parent end, and is value-identity at runtime, so it is sound only when it names the declared sorts: the cast TARGET sort must equal the parent end’s declared sort, and the CHILD end’s declared sort must be a subsort of (or equal to) it. Casting to a third sort would frame the parent row at a sort the parent relation does not hold; a child end whose sort is unrelated to the parent’s is a type error, not a widening cast. Fix: cast to the parent end’s declared sort exactly, and ensure the child end’s sort is a subsort of it (declare the subsumption with specializes / <:); if the two sorts already agree, drop the cast and use a plain rename. Fail-open: the gate fires only when both sorts are known in scope.
OE1424ErrorLiveMappedSubsumptionDivergentDiamondA relation reaches the same ancestor through two subsumption paths whose composed argument mappings onto that ancestor DIFFER (a divergent-map diamond). Because the two compositions disagree, one child fact would translate to two different ancestor rows, and a family query over the ancestor follows only the first path in the subsumption-image closure — so it would silently report one framing and drop the other. Silent under-report is the worst failure shape, so the diamond is refused at declaration. A diamond whose paths compose to the SAME mapping is harmless and stays legal. The message names the child, the ancestor, and both paths with their composed mappings spelled out as parent-name-keyed fillers. Fix: reconcile the fillers so both paths compose to the same mapping onto the ancestor, or remove one subsumption edge. If both images are genuinely wanted — the child should occupy both ancestor rows — that is a feature request; the mapped-relation-subsumption design record keeps both-images support open as future work.
OE1425ErrorLiveMutateEndpointValueInConceptSlotA mutate body’s insert R(...) places a literal value in a relation endpoint whose declared type is a concept. A value can never inhabit a concept’s extent — an individual and a value are different sorts — so the tuple is provably wrong independently of any world assumption or of what is classified at run time. The same tuple written as a ground pub fact R(...) was already refused for exactly this reason; accepting it from a mutate body committed a tuple whose endpoint contradicted the relation’s own signature, and queries then served the raw value in a slot declared to hold an individual. The message names the relation, the endpoint position and its declared concept, and the offending literal. Fix: pass an individual of the declared concept in that position, or change the relation’s declared endpoint type to the primitive type the value actually has. Refused before the artifact is written, so no .oxbin carries the bad tuple; the whole mutate body is rejected, not silently narrowed.
OE1426ErrorLiveMutateEndpointDisjointConceptA mutate body’s insert R(...) places a value whose statically declared concept is disjoint from the endpoint’s declared concept, where the disjointness is asserted by a disjoint { ... } or partition ... { ... } group (lifted through subtyping: a subtype of a disjoint member is disjoint from the other member). Because the group declares the two concepts pairwise non-overlapping, no individual can ever be classified under both, so the tuple can never be satisfied in any reachable state — this is a schema-level contradiction, not a fact about the current state. Two concepts with NO declared disjointness are left accepted: multiple classification is legal, an individual under one may later also be classified under the other, and refusing that would be unsound in the other direction. The message names the relation, the endpoint position and its declared concept, the offending value’s declared concept, and the group that makes them disjoint. Fix: pass a value of the endpoint’s declared concept, widen the endpoint’s declared type to a common supertype outside the disjoint group, or drop the disjointness declaration if the two concepts were never meant to be exclusive.
OE1427ErrorLiveRelationEndpointValueInConceptSlotA write places a plain value in a relation endpoint whose declared type is a concept. An individual and a value are different sorts, so the value can never inhabit the concept’s extent and the tuple is provably wrong regardless of the concept’s world assumption or of anything classified at run time. This is distinct from the refusal that fires when an endpoint individual exists but is classified under nothing: that one turns on the world assumption, whereas this one needs no assumption at all — nothing can make a number an individual. The message names the relation, the endpoint position and its declared concept, and the offending value. Fix: write an individual of the declared concept in that position, or declare the endpoint with the primitive type the value actually has. Raised before the tuple is buffered, so the enclosing mutation body commits nothing.
OE1428ErrorLiveRelationEndpointDisjointConceptA write places an individual in a relation endpoint whose declared concept is disjoint from a concept the individual is already classified under, where the disjointness is asserted by a disjoint { ... } or partition ... { ... } group (lifted through subtyping on both sides: a subtype of a disjoint member is disjoint from the other member). The group declares its members pairwise non-overlapping, so classifying the individual under the endpoint’s concept would itself be refused as a group violation — the tuple can therefore never be satisfied in any reachable state. This does not depend on the endpoint concept’s world assumption: an open world permits unknown membership, but not membership that a declaration forbids. When the individual is classified only under concepts with NO declared disjointness from the endpoint’s concept, the write is ACCEPTED and this diagnostic does not fire — multiple classification is legal and the individual may later also be classified under the endpoint’s concept. The message names the relation, the endpoint position and its declared concept, the individual, and the conflicting concept it is classified under. Fix: classify the individual under the endpoint’s declared concept (which requires it not to be in a disjoint group with its current classification), pass a different individual, or reconsider the disjointness declaration. Raised before the tuple is buffered, so the enclosing mutation body commits nothing.
OE1429ErrorLiveRelationSubsumptionUnknownParentA relation declares <: Parent, but Parent resolves to no declared relation: it is not declared in the same file, and it does not name exactly one workspace-visible pub relation (by unique short name, or by unique exact/suffix match for a qualified path). Accepting the clause would persist a subsumption edge against a relation that does not exist, so the declared flow-up could never deliver a tuple anywhere — the declaration would type-check and change nothing, silently. The message names the child relation and the unresolved parent path. Fix: declare the parent relation, make the reference unambiguous (qualify the path), or remove the <: clause. An ambiguous short name — two visible relations sharing it — also lands here after the unique-resolution step fails; qualify the path to pick one.
OE1430ErrorLiveInconclusiveMembershipBlockedA blocking (Severity::Error) check cannot be discharged for a subject the write introduces: its firing verdict depends on membership in a computed concept that the well-founded semantics leaves UNDETERMINED at the write point (a Can verdict — a negation/defeat standoff, or an open-world absence of evidence), so the check is neither definitely violated nor definitely satisfied. Admitting the write would commit data whose governing constraint could not be decided; firing the check would be a false accusation of a violation that is only possible, not established. Neither is honest, so the write is refused (fail-closed). The message names the check, the subject, and the undetermined membership the verdict depends on. Remedies, in order: make the membership decidable — establish the classifying evidence for the subject, or break the negation/defeat standoff among the classifying rules so the concept settles to a definite verdict; OR, if the check should not block on an undetermined verdict, lower its severity to Warning/Info (or mark it #[observe]) so it reports at undefined grade instead of blocking.
OE1431ErrorLiveDeterminednessTestOutsideCheckPlaneThe determinedness test undetermined(...) / determined(...) reads whether a membership atom’s verdict is left UNDEFINED (Can) by the well-founded semantics. That read is sound only in a check body, which runs AFTER the fixpoint has converged and contributes nothing back to it — a post-fixpoint consumer reading a settled value. Used in a derive/query/bridge body the same read is truth-value reflection feeding the fixpoint: a rule that contributes to the model would let its own firing depend on the in-progress undefinedness of the model it is helping to compute, a non-monotone self-reference the well-founded semantics has no fixpoint for. So the operator is refused outside the check plane. The refusal also fires when the argument is not a membership atom of the check body (the operator guards the check’s own membership atoms, not an arbitrary atom). Remedies: move the determinedness test into a check body (the only plane where it is meaningful); or, if a derive must react to a standoff, restructure so the classifying rules settle to a definite verdict rather than reading their own undefinedness.
OE1432ErrorLiveRuleAtomArgSortMismatchAn entity-typed argument position in a derive / check / bridge rule-body atom (or a bridge head atom) is given a logic variable whose statically DECLARED sort is <:-incomparable with the predicate’s declared parameter concept — neither a subtype nor a supertype of it on the declared <: lattice. A variable’s declared sorts are the ones the program itself asserts: its head-parameter annotation, any body sort guard (x : T), and any unary concept-membership atom (T(x)); types a variable merely picks up by occupying other predicates’ argument slots are classification evidence, not declarations, and never trigger this refusal. A subtype in a supertype slot passes (ordinary subsumption); a supertype in a subtype slot passes (the atom is a membership join, so it narrows — the same direction an x : T occurrence-typing test narrows); only the <:-incomparable pair is refused. A predicate declared in several clauses — one per admissible sort — licenses an argument comparable with ANY clause’s parameter concept at that position, and a clause leaving the position unannotated admits anything there. This is deliberately NOT a runtime-disjointness claim: Argon individuals are multiply classified, and two <:-incomparable concepts can share instances — the refusal is the static-sort discipline of the declared signatures (the OE0665 precedent), because an atom whose declared sorts are incomparable can only succeed through a multi-classification the program never states, and in practice it compiles to a silently-empty join surfacing as mass downstream wrong answers with no pointer to the ill-typed atom. To state the multi-classification deliberately, assert the second sort in the body (x : T, or the membership atom T(x)) — that assertion licenses the atom. The message names the variable, its declared sort(s), the predicate, and the parameter’s declared concept(s), at the argument’s span.
OE1433ErrorLiveAggregateProjectionNotNumericA value aggregate (sum / avg / min / max) folds a projection whose type is statically known to be non-numeric — a temporal value (Date / DateTime / Time / Duration / Instant), a String, a Bool, or an entity/structured value — where the fold’s domain is the exact numeric tower (Int / Real / Decimal / Money / Nat). All four value folds are numeric in both evaluation planes: the rule-plane fold lifts every projected value into the exact-rational domain, and the fn/compute-plane min / max / sum / avg do the same — min / max do NOT order non-numeric values (an ordered comparison over them is its own gate), so no orderable-but-non-numeric projection is admissible either. Refused at ox check / ox build when the projection’s declared type proves the mismatch (naming the projection expression, its type, and the aggregate’s numeric domain); the same code is raised loudly by the runtime fold if a non-numeric value reaches it dynamically, in place of the historic internals-leaking internal reasoning engine error: … got Date(<epoch days>). Evidence-gated: a projection whose type is unknown or generic is left to the runtime gate. Project a numeric field or expression into the fold; to count rows or fold something else, use count, or model the value numerically.
OE1434ErrorLiveMutateFieldValueDisjointConceptA mutate body writes into a concept-typed field — an insert T { f: v } field initializer or an update ... set { f = v } assignment — a value whose statically declared concept is disjoint from the field’s declared concept, where the disjointness is asserted by a disjoint { ... } or partition ... { ... } group (lifted through subtyping: a subtype of a disjoint member is disjoint from the other member). Because the group declares the two concepts pairwise non-overlapping, no individual can ever be classified under both, so the value can never satisfy the field’s declared type in this state or any later one — this is a schema-level contradiction, not a fact about the current state. A concept-typed field is a typed slot exactly as a relation endpoint is, and this is the field-side counterpart of the endpoint refusal; the two write planes do not hold private rules for the same question. Two concepts with NO declared disjointness are left accepted: multiple classification is legal, an individual under one may later also be classified under the other, and refusing that would be unsound in the other direction. A value that already satisfies the field’s own concept (under that concept or a subtype of it) is likewise accepted — the field’s demand is met, and an overlap the value also carries with a declared-disjoint sibling is the group axiom’s own overlap refusal to make against the classification declarations, not this write’s to make against the field. The gate is per-file and abstains rather than refusing where it cannot establish agreement with the runtime write gate: a field whose declared concept type is not declared in this file, a value term whose sort is not statically in hand (a projection, a call result, a rebound binder), and an individual whose complete classification set this file cannot see all defer to the runtime gate, which reads the value’s real classification and is the total authority there. The message names the field and its declared concept, the offending value and its declared concept, and the group that makes the two disjoint. Fix: write an individual of the field’s declared concept, widen the field’s declared type to a common supertype outside the disjoint group, or drop the disjointness declaration if the two concepts were never meant to be exclusive.
OE1435ErrorLiveFieldValueDisjointConceptA write places an individual in a concept-typed field whose declared concept is disjoint from a concept the individual is already classified under, where the disjointness is asserted by a disjoint { ... } or partition ... { ... } group (lifted through subtyping on both sides: a subtype of a disjoint member is disjoint from the other member). The group declares its members pairwise non-overlapping, so classifying the individual under the field’s declared concept would itself be refused as a group violation — the field value can therefore never satisfy the declared type in any reachable state. A concept-typed field is a typed slot exactly as a relation endpoint is, and this is the field-side counterpart of the endpoint refusal; the two write planes do not hold private rules for the same question. This does not depend on the field concept’s world assumption: an open world permits unknown membership, but not membership that a declaration forbids. When the individual is classified only under concepts with NO declared disjointness from the field’s concept, the write is ACCEPTED and this diagnostic does not fire — multiple classification is legal and the individual may later also be classified under the field’s concept. An individual that already satisfies the field’s own concept (under that concept, a subtype of it, or a rule-derived membership of it) is likewise accepted: the field’s demand is met, and an overlap it also carries with a declared-disjoint sibling is what the group axiom’s own overlap check exists to refuse, against the classification that created it rather than against this write. Classification is read against the write’s own read-your-writes view, so classifying the individual earlier in the same mutation body satisfies the gate. The message names the field and its declared concept, the individual, the conflicting concept it is classified under, and the declared group members that prove the conflict. Fix: classify the individual under the field’s declared concept (which requires it not to be in a disjoint group with its current classification), write a different individual, or reconsider the disjointness declaration. Raised before the buffered write is applied, so the enclosing mutation body commits nothing.
OE1441ErrorLiveRuleUnknownTruthQualifierInvalidThe executable truth qualifier is exactly R(arguments) is unknown: after R’s well-founded component converges, it reads R’s $undefined::R companion, containing tuples that are neither definitely true nor definitely false. The stratifier gives that read a strict dependency on R, so the consumer runs later. OE1441 refuses two classes that cannot use this meaning safely. First, is not unknown, is unknown(payload), and path-headed x is unknown do not select one predicate companion; silently treating them as an ordinary atom would return definite rows and answer a different question. Rewrite as an unnegated, payload-free predicate call; complements require an explicit finite domain and separate rules. Second, a consumer that feeds back into R’s own recursive component would inspect $undefined::R before R converges. Move that consumer to a separate higher-stratum derive that does not feed back into R. Concrete rewrite: remove any dependency from Voter or its recursive peers back to UnknownVoter; let that component finish, then add pub derive UnknownVoter(p) :- Person(p), Voter(p) is unknown;. ox derive target/root.oxbin Voter prints the component’s unknown tuples as Can rows; the new head turns those tuples into definite UnknownVoter rows. The multi-valued outcomes is both, is ambiguous, and is timeout remain the separate OE1349 feature.
OE1442ErrorLiveShapeClauseMemberNotEntitySortedA concept whose membership is decided by a shape clause (pub type C iff Shape(self, …)) would classify VALUES, not entities: head parameter 0 of the shape derive — the parameter that receives each classified member — is value-sorted (a primitive such as Int or String, or a struct/enum-declared type). Concept membership ranges over entities: iof(x, T) takes an entity in its subject position and a concept’s extent is a set of entities, so a value can never be a member of a concept, and asking for the metatype or the extent of language-level data is a category error. Left to compile, the concept’s extent would contain plain values, the membership read would answer true for them, and the whole-domain reflection read would return them beside real individuals. Fix: give the shape derive an entity-typed member column — annotate parameter 0 with the concept whose individuals are being classified, and bind it in the derive body to a position that holds that individual (typically a membership atom T(m) or an entity end of a relation) — or, when the thing being classified really is a value, model it as a FIELD of an entity and classify the entity instead. Declaring the concept’s supertype (pub type C <: P iff Shape(self);) also bounds the member column, since the synthesized membership rule then conjoins membership in P.

Cross-level instantiation bodies (19xx)

Field-coverage gates for cross-level instantiation bodies (§5.2). The MLT reasoning codes (categorization / partition / order / subordination / powertype) that once sat here are gone — MLT is an unprivileged package (packages/mlt), so those constraints are authored as the package’s own rules/checks over the neutral substrate, not as reserved compiler codes.

CodeSeverityStatusNameMeaning
OE1901ErrorReservedInstantiationFieldNotInTargetA cross-level instantiation body assigns = to a field absent from the target metatype (§5.2).
OE1902ErrorReservedInstantiationFieldShadowsA cross-level instantiation body declares a : field that shadows an inherited field (§5.2).
OE1908ErrorReservedIntrinsicPropertyMissingA cross-level instantiation body fails to bind a #[intrinsic] field required by the target metatype (§8).

Collection operators (24xx)

CodeSeverityStatusNameMeaning
OE2403ErrorLiveNonIterableForSourceA for x in EXPR { … } loop in a mutate / fn body iterates a source whose type is provably not iterable — a scalar (Int, String, Date, …), a concept / struct, a tuple, or a function value. A for body ranges over a COLLECTION ([T] / List<T> / Set<T>) or an OPTIONAL (T? — the zero-or-one “insert-if-present” idiom: an absent optional runs the body zero times, a present one exactly once). Before this gate the checker inferred the iterand’s type but never constrained it, so for x in <scalar Int> passed ox check and then either died at runtime with `for` iterable must be a collection or — once a present optional is admitted as a one-element loop — silently iterated a genuine scalar exactly once. Refused at ox check / ox build instead, the same fail-closed discipline as OE0230 (insert … into a non-collection field) and aligning the Rust checker with the Lean forLoop semantics, which requires a list-shaped source. An iterand of no statically-known type (Unknown, a generic application such as Set<T>, a bound generic parameter, Top) carries no proof of non-iterability and stays silent — no cascade. Iterate a collection or an optional, or hoist the scalar into a one-element list ([x]).
OW2402WarningReservedRefineSingletonAsOptionA refinement [T; <=1] is more naturally expressed as T? (Option<T>) (§5.3).

Explanations

Codes with an extended explanation (also available offline via ox explain <CODE>):

OE0204 — UnknownField

Field access x.f where the receiver’s established type declares no field f (counting inherited fields and any : T narrowing in scope). In a rule body the error fires only on provable absence: an Argon individual can be classified under several concepts, and a field on any established concept is admitted, so f must be missing from every one of them. A receiver with no established concept (an unbound variable, or a path to a declared type/enum) is skipped.

Fix: declare the field on the concept, narrow the receiver to a type that has it, or correct the field name.

use std::core::{type, rel};

pub type Person { name: String, age: Nat }

pub derive adult(p) :- p: Person, p.age >= 18;   // ok: `age` is on Person
pub derive bad(p)   :- p: Person, p.income > 0;  // OE0204: no `income` on Person

OE0211 — IofInsertOnDefined

A concept defined with iff is defined, not asserted: its membership is derived, so you cannot write membership into it manually — the substrate classifies individuals automatically whenever the definition holds. There are two defined forms:

  • A braced-iff concept (iff { … }) derives membership from its refinement predicate over the individual’s fields.
  • A shape-defined concept (iff <Shape>(self)) derives membership from a synthesized rule over relations/facts.

(A primitive concept declared with where is the opposite: membership is asserted, and insert iof is exactly how you assert it.)

insert iof / delete iof into either defined form is refused — membership is single-source, never asserted. Constructing an instance of a shape-defined concept (insert C { … }), or of a subtype beneath one, is refused for the same reason: construction buffers an asserted iof, and a shape concept’s relational evidence can never be supplied by a construct. A braced-iff concept is constructible — its predicate evaluates over the constructed fields, so its extent stays honest.

Fix — write the underlying state the definition reads, and let classification follow:

use std::core::{type, rel};

pub type Adult <: Person iff { self.age >= 18 };

pub mutate seed() {
    insert Person { name: "Mia", age: 19 };   // not `insert iof Adult`
    // Mia classifies as Adult automatically (age >= 18).
}

For a shape-defined concept, construct the supertype and assert the relations/facts its shape derive reads.

The same applies through <:-ancestors: if any defined ancestor derives the membership, the write is refused — asserting (or constructing) a descendant would assert the single-source ancestor.

OE0213 — IofInsertIntoBot

Bot () is the empty concept — the lattice bottom. By definition it has no instances: nothing is ever an instance of Bot. So insert iof(x, Bot) asserts a contradiction (x is a member of a category that, by definition, is empty) and is refused statically.

This is a sound, unconditional refusal — it follows from Bot’s definition alone, not from any two-concept disjointness analysis (that stays reserved). The dual, Top (), is the opposite: every individual is an instance of it, so a rule body Top(x) ranges over the whole domain.

If you meant to assert membership in a real concept, name that concept:

pub type Person;

pub mutate seed(p: Person) {
    insert iof(p, Person);   // not `insert iof(p, Bot)`
}

OE0605 — UnknownMetatype

Argon has no built-in ontology vocabulary. A declaration like pub kind Person reads kind as a classifier, and classifiers are not keywords — the leading introducer must resolve to a pub metatype that is in scope (§3.4). That is what keeps the language ontology-neutral: kind, class, rigid_sortal and friends ship in vocabulary packages (UFO, BFO, …), never in the compiler.

Even the no-commitment baseline type/rel are not ambient: they live in std::core and must be imported.

Fix — bring the baseline into scope:

use std::core::{type, rel};
pub type Person;            // ontology-uncommitted

or commit to a vocabulary you declare or import:

pub metatype kind = { };    // declares the `kind` classifier
pub kind Person;            // now legal

To make the baseline available across a whole package, set prelude = ["std::core::{type, rel}"] under [package] in ox.toml.

OE0668 — RefinementInvariantViolated

A primitive concept declared with where carries a necessary invariant: every member must satisfy it. This write would place an individual in the concept while the predicate evaluates to a definite false, so it is refused.

Three-valued by design: only a definite false blocks the write. If the predicate is unknown (a field the data has not supplied yet), the write is allowed — absence of information is not a violation.

use std::core::{type, rel};

pub type Adult <: Person where { self.age >= 18 };

pub mutate admit() {
    insert Adult { name: "Lee", age: 15 };   // OE0668: 15 >= 18 is definitely false
    insert Adult { name: "Ada", age: 21 };   // ok
    // age unknown -> allowed (unknown, not false)
}

Fix: write a value that satisfies the invariant, model the looser set with a weaker where, or — if membership should be derived rather than asserted — use an iff definition instead.

OE0239 — FactReferencesDerivedPredicate

A predicate in Argon has a single origin: its extent is either EXTENSIONAL (asserted as ground facts) or INTENSIONAL (computed by derive/query rules) — never both. pub fact P(...) asserts into an extensional relation, but here P is a rule head, so the seed fact would key a different relation node than the rule reads and silently drop out of the fixpoint: no error, wrong answer. Argon refuses at ox check / ox build rather than emit an artifact that mis-derives.

To give a derived predicate ground tuples, keep it single-origin: seed the head with a bodiless derive clause, or read a base relation. Note that rule bodies must be range-restricted — bind each head variable with a positive atom, not a bare comparison (p.income > 0 alone leaves p unbound):

use std::core::{type, rel};

// a base relation the rule reads (seed it with `pub fact HighEarner(...)`),
// unioned with the rule clauses over the same head:
pub rel HighEarner(mut p: Person);
pub derive owes_tax(p) :- HighEarner(p);
pub derive owes_tax(p) :- p: Person, p.income > 0;