ADR-0031: Entity types, not entity kinds — de-overloading 'kind'
ADR-0031: Entity types, not entity kinds — de-overloading ‘kind’
Status: accepted (2026-07-04)
Supersedes: partially supersedes ADR-0028
— the wire key naming only (from.kind → from.entity_type; has_link.kind →
link_type). ADR-0028’s decision stands in full: QuerySpec is the wire surface, IR-2
stays kernel-internal, the flat-v2 where grammar and its staging discipline are unchanged.
Context
The word kind was overloaded. The LLD (§20) always names the modeled type of an
entity an entity type (defineEntityType, EntityType | Interface link targets,
“entity types conform structurally”) and reserves “kind” for the kind constructor —
the closed set of nine value shapes (text, numeric, categorical, … the layer-1
primitive a trait’s value is built from). But the code drifted: EntityKindDecl,
entity_kinds, kind_id, EntityKindId, EntityRef.kind — using “kind” for the
entity type, colliding head-on with KindConstructor (the constructor) inside the same
files, and with a third, orphaned vinxi-value::ValueKind. A late glossary rewrite
compounded it, defining “Entity / Entity Kind” on the one page that declares itself
“authoritative over any conflicting page” — inverting the LLD’s own vocabulary.
The ratified query wire inherited the collision: ADR-0028 §v0 serves
from (kind | kinds | interface), where kind means entity type.
This ADR is the naming half of the ontology-depth design
(docs/superpowers/specs/2026-07-04-ontology-palantir-depth-design.md, R1/R10); the
value-type layer (R2) and YAML authoring (R8) are tracked separately.
Decision
The modeled type of an entity is an entity type. “kind” is reserved for the kernel constructor layer. Concretely:
- Document format & code:
EntityTypeDecl,entity_types,entity_type_id,EntityTypeId,EntityRef.entity_type, snapshotentity_type()/type_conforms(); link endpointssource_type/LinkTarget::Types; the amendment/derivation/alert fieldsentity_type_id/root_type/from_type/alert_type. - Query wire (partial supersession of ADR-0028):
from.kind→from.entity_type(one key, accepting a single string or an array — the pre-existing union shape, unchanged);has_link.kind→link_type(it names a link type). The response envelope fieldkindId→entityTypeId. Grammar, flat-v2 shape, conformance discipline, and the IR-2-internal ruling are untouched. - The glossary is corrected to “Entity / Entity Type”; this ADR adjudicates the self-declared-authoritative page in favour of the LLD vocabulary.
- The constructor layer keeps “kind” for now (
KindConstructor, the{"kind": …}trait-value tag). Its rename tovalue_kind, and the vocabularyvalue_kind → value_type → trait → entity_type, land with the value-type-layer track (a later ADR under the same spec). Ambient, non-entity senses of “kind” (statement_kind,job_kind,dataset_kind, eventEntityChangeKind, …) are unaffected.
Consequences
- The rename is breaking across the document format, the query wire, migration SQL, the truth-log subject strings, and the provisional TS client. It was executed clean-slate (spec R9): no persisted universe or database was preserved, so no serde aliases, dual-read, or in-place data migration exist — dev environments drop and reinstall.
- The six repo reality packages were migrated to the new format in the same slice, and a
new
validate()guard rejects a declaration-free document (the failure mode where an old-format document deserializes silently-empty because every section is#[serde(default)]). - Two closed “kind” vocabularies remain by design, but they no longer collide in naming: the value-kind constructor layer (kernel-owned, nine shapes) and the ambient record categories. The entity sense is gone.
- A follow-on ADR completes the constructor-layer rename to
value_kindand introduces the value-type layer; until then, “kind constructor” in canon still reads asKind*in code — a known, scheduled inconsistency.