k2atlas is the definition-driven engine for structured listings.
It exists to provide one common data model for many listing types that have different domain payloads but the same outer shell and operational behavior.
Examples:
- hotel listing
- room listing
- book listing
- book-series listing
- dating profile listing
- car listing
See also k2atlas/LISTING_MODEL.md for a sharper definition of the canonical listing object, sublisting model, and standard read projections.
k2atlas exists to solve the repeated complexity around structured listings once, generically, instead of rebuilding it inside each product.
The trivial part is storing a record and reading it back.
The hard part is everything around it:
- slug rules and stable URL identity
- media ingestion
- hero image selection
- gallery management and ordering
- structured sections
- publication state
- ranking and weighting
- taxonomy
- locality and containment
- one-to-many composition
- variants and child listings
- filtering
- aggregation
- list-card and detail-page composition
- editorial curation
- search indexing
- duplication and canonicalization
- permissions and workflow
These pressures recur across many domains even when the payload differs.
Examples:
- dating profile
- hotel
- room type
- restaurant
- beach
- excursion
- car rental
- business profile
- marketplace item
The domain-specific fields vary, but the surrounding listing structure is largely the same.
k2atlas is not:
- raw storage
- authentication
- authorization
- messaging
- page rendering
- a generic CMS blob store
- a page builder
- a generic graph engine
k2atlas is the shared listings model that turns typed listing definitions into canonical, filterable, rankable, render-ready records.
Within the wider platform:
k2dbpersists canonical listing records and projectionsk2loginauthenticates actorsk2rbacauthorizes listing and workflow operationsk2mxemits and consumes lifecycle eventsk2atlasdefines listing kinds, common shell fields, composition rules, and derived read surfaces
The abstraction is not that many internet objects happen to share a few fields.
The abstraction is that many internet listings are instances of the same operational form: a structured listing that must be published, surfaced, filtered, composed, ranked, and acted upon.
k2atlas should model the invariant shell of publishable listings, while domain definitions supply only the variable payload.
The canonical core must stay small and invariant.
If it becomes a giant optional-field union, the system collapses back into a weak blob model.
The first-pass canonical listing record is AtlasEntity with the following top-level structure:
idkindslugtitlesummarymediasectionstaxonomylocalityvisibilitylifecycleactionsorderingmembershipsfacets
id
- Stable canonical identity.
kind
- Declared listing kind from contract data.
- Examples:
hotel,restaurant,dating_profile,room_type,beach.
slug
- Stable human-facing URL identity for a listing.
- May be unique globally or within a scope depending on package rules.
title
- Primary human-facing label.
summary
- Short human-facing description.
media
- Canonical media attachments and ordering.
- Main image, gallery, captions, crop intent, sort order, alternates.
sections
- Structured content areas that make a listing renderable without becoming a freeform CMS.
- Examples: overview, amenities, policies, specifications, highlights, editorial notes.
taxonomy
- Explicit classifications.
- Categories, tags, segments, themes, collections, editorial labels.
locality
- Place semantics.
- Country, region, city, area, coordinates, containment references, service radius.
visibility
- Who can see the entity and under what conditions.
lifecycle
- Draft, review, published, archived, revoked, scheduled, expired.
actions
- What a consumer can do with the listing.
- Examples:
view,book,message,call,apply,buy,compare,visit,save.
ordering
- Sort weight, boosted rank, pinned state, freshness inputs, editorial priority.
memberships
- One-to-many composition.
- Examples: hotel contains room types, series contains books, venue contains events.
- Ordered membership is first-class where child order matters.
facets
- Domain-specific payload through explicit typed facets only.
The first implementation should treat the atlas model as a small set of explicit contract objects.
These objects are the listing-model surface that CUE definitions describe and that Rust validates, normalizes, stores, and projects.
AtlasEntity is the canonical listing record.
It represents a discoverable, publishable listing with stable identity and typed structure.
Conceptual shape:
AtlasEntity {
id: EntityId
kind: KindId
title: LocalizedText
summary?: LocalizedText
media?: MediaSet
taxonomy?: TaxonomySet
locality?: LocalityRefSet
visibility: VisibilityPolicy
lifecycle: LifecycleState
actions?: [Action]
ordering?: OrderingPolicy
relations?: [Relation]
memberships?: [Membership]
correspondences?: [Correspondence]
facets: FacetPayloadSet
provenance?: Provenance
}
Required invariants:
- every entity has exactly one canonical
id - every entity has exactly one declared
kind - every listing may only carry declared facets for its
kind - every membership must satisfy the child/member rules declared by that
kind - no undeclared top-level semantic fields may appear in canonical storage
Relation is an optional secondary typed edge between listings.
It may express supporting connection where the listing model needs it, but it is not the center of Atlas.
Conceptual shape:
Relation {
type: RelationType
source_id: EntityId
target_id: EntityId
target_kind: KindId
direction: Direction
cardinality?: Cardinality
inverse?: RelationType
role?: RoleId
metadata?: ValueMap
}
Examples:
- hotel
located_inarea - room type
variant_ofhotel - book
written_byauthor - restaurant
nearbeach
Required invariants:
- a relation must always have a declared
type - target kinds must satisfy the contract for that relation type
- relation metadata must be schema-bound, not ad hoc
- relations do not imply equality or substitution unless a correspondence declares that separately
Membership is the core one-to-many composition edge.
It is used when a listing includes exact child listings in a defined sequence or slot structure.
Conceptual shape:
Membership {
type: MembershipType
source_id: EntityId
target_id: EntityId
target_kind: KindId
position: u32
label?: string
required?: bool
metadata?: ValueMap
}
Examples:
- series contains books in reading order
- guide contains curated listings in editorial order
- hotel presents room types in preferred display order
Required invariants:
- memberships are ordered by explicit
position, never by insertion accident - membership semantics are directional
- duplicate positions are invalid unless the membership type explicitly allows ties
- membership is composition, not loose relation
Correspondence is the typed mapping between entities that are related by sameness, versioning, substitution, fulfillment, or variant semantics.
It exists specifically to avoid naive equality.
Conceptual shape:
Correspondence {
type: CorrespondenceType
source_id: EntityId
target_id: EntityId
target_kind: KindId
direction: Direction
strength: CorrespondenceStrength
metadata?: ValueMap
}
Examples:
- purchased item
fulfillspublic item - edition 2
supersedesedition 1 - public listing
public_variant_ofconceptual work - commercial listing
commercial_variant_ofconceptual work
Required invariants:
- correspondence must be explicit and typed
- correspondence is not assumed to be symmetric
- correspondence does not collapse canonical identity
- source and target may be semantically linked while remaining operationally distinct
The objects have different responsibilities and must not be conflated.
AtlasEntitydefines the canonical thingRelationdefines typed semantic connectionMembershipdefines ordered compositionCorrespondencedefines typed non-identity mapping
This separation is necessary to model domains like hospitality, marketplaces, and publishing without collapsing everything into one edge model.
The contract objects depend on a small set of shared value types.
These types must be canonical, deterministic, and reusable across all kinds.
The first pass should define at least the following.
EntityId
- stable canonical entity identifier
- opaque to clients
- globally unique within atlas
KindId
- stable identifier for a declared entity kind
- examples:
hotel,room_type,author,book,series
RelationType
- stable identifier for a declared semantic edge type
MembershipType
- stable identifier for an ordered composition edge type
CorrespondenceType
- stable identifier for a declared non-identity mapping type
RoleId
- stable identifier for a role-bearing relation meaning
- examples:
lead_author,contributor,translator,editor,illustrator
LocalizedText
- canonical localized text object
- should support explicit locale keys
- must not rely on inferred language from content
Conceptual shape:
LocalizedText {
default_locale: LocaleId
values: {
[locale: LocaleId]: string
}
}
LocaleId
- stable locale identifier such as
en,en-GB,th,de
MediaAssetRef
- reference to a managed media object
- carries identity, not embedded binaries
MediaSet
- canonical media container for a listing-like entity
- supports main asset, gallery, alternates, ordering, and descriptive metadata
Conceptual shape:
MediaSet {
primary?: MediaAssetRef
gallery?: [MediaEntry]
alternates?: [MediaEntry]
}
MediaEntry {
asset: MediaAssetRef
position: u32
caption?: LocalizedText
alt?: LocalizedText
intent?: MediaIntent
}
TaxonomySet
- canonical classification container
- categories, tags, segments, themes, editorial labels, collection ids
LocalityRef
- reference to a place-like entity or canonical locality record
LocalityRefSet
- ordered or typed collection of locality references
- supports hierarchical containment and service-scope semantics
VisibilityPolicy
- declared policy describing who may discover or view an entity
- examples:
private,authenticated,public,scheduled_public
LifecycleState
- declared workflow state
- examples:
draft,review,published,archived,expired,revoked
OrderingPolicy
- canonical ordering container
- supports editorial weight, pinning, freshness, boost windows, and deterministic tie rules
Direction
- relation orientation marker
- examples:
outbound,inbound,bidirectional
Cardinality
- declared allowed multiplicity
- examples:
one,optional_one,many,bounded_many
CorrespondenceStrength
- describes how strong or substitutable a mapping is
- examples:
equivalent,variant,supersession,fulfillment,partial
ValueMap
- schema-bound metadata bag
- only allowed where the contract explicitly declares metadata structure
- never an escape hatch for undeclared semantics
FacetPayloadSet
- collection of declared facet payloads bound to a specific
kind - each facet payload must validate against its declared facet contract
Provenance
- source-of-truth and import lineage data
- supports ingestion, synchronization, and audit use cases without leaking operational details into the semantic core
The following examples are not final schemas.
They exist to show how atlas kinds should be expressed semantically.
hotel is a publishable hospitality entity.
It uses shared atlas semantics plus hospitality-specific facets.
Conceptual definition:
kind hotel {
core:
title
summary
media
taxonomy
locality
visibility
lifecycle
ordering
facets:
hospitality
amenities
pricing
availability
contact
geo
seo
relations:
located_in -> area | city | region
belongs_to -> brand?
has_variant -> room_type*
related_to -> restaurant* | beach* | excursion*
projections:
list_card
detail_page
map_card
filters:
locality
amenities
price_band
rating
}
room_type is a publishable variant entity.
It is not just a field on a hotel. It has independent semantics but depends on a parent hotel relation.
Conceptual definition:
kind room_type {
core:
title
summary
media
visibility
lifecycle
ordering
facets:
hospitality
amenities
pricing
availability
relations:
variant_of -> hotel exactly_one
located_in -> area? | city?
correspondences:
same_concept_as?
public_variant_of?
commercial_variant_of?
projections:
list_card
booking_panel
comparison_row
}
author is a publishable profile entity.
Conceptual definition:
kind author {
core:
title
summary
media
taxonomy
visibility
lifecycle
ordering
facets:
profile
editorial
contact
seo
relations:
related_to -> book*
located_in -> place?
projections:
list_card
profile_page
}
book is a publishable work or edition-like entity depending on the declared domain contract.
Conceptual definition:
kind book {
core:
title
summary
media
taxonomy
visibility
lifecycle
ordering
facets:
editorial
commerce
inventory
seo
relations:
written_by -> author one_or_more role_bearing
contributed_by -> author*
belongs_to -> publisher?
memberships:
part_of -> series*
correspondences:
edition_of?
supersedes?
fulfills?
public_variant_of?
commercial_variant_of?
projections:
list_card
detail_page
purchase_card
}
series is a canonical entity with ordered composition semantics.
It proves that atlas must support membership separately from ordinary relations.
Conceptual definition:
kind series {
core:
title
summary
media
taxonomy
visibility
lifecycle
ordering
facets:
editorial
seo
memberships:
contains -> book* ordered
relations:
related_to -> author* | publisher*
projections:
list_card
series_page
}
The split between CUE and Rust should be deliberate.
CUE definitions should declare:
- kinds
- facets
- relation vocabularies
- membership vocabularies
- correspondence vocabularies
- field requirements
- normalization rules expressible as contract data
- lifecycle and visibility policies
- projection shapes
- query and sort surfaces
Rust should own:
- loading and validating CUE packages
- canonical normalization and compilation
- deterministic storage projection
- runtime validation of entity instances
- relation, membership, and correspondence enforcement
- query planning
- projection materialization
- event emission and operational workflows
The rule is simple:
contract semantics live in CUE, execution semantics live in Rust.
Neither side should guess what the other meant.
k2atlas only has value if its behavior is deterministic, canonical, and mechanically derived from explicit contract data.
The following invariants are mandatory.
- every
kindmust be declared explicitly - every facet used by a
kindmust be declared explicitly - every relation, membership, and correspondence type must be declared explicitly
- every top-level semantic field in canonical storage must be declared explicitly
- undeclared fields are invalid unless the contract explicitly defines an extension surface
The system must not infer semantics from payload shape alone.
- canonical entity identity is never inferred from title, slug, or field similarity
- semantic correspondence never replaces canonical identity
- equality, variant, edition, fulfillment, and supersession are distinct mapping types
- identity mappings must be directional unless the contract explicitly declares symmetry
- multiple identity layers may coexist, but they must be named and typed explicitly
The system must not collapse "related" into "same".
- list ordering must be derived from explicit ordering policy or explicit membership position
- tie-breaking rules must be deterministic and contract-defined
- insertion order is never a valid semantic ordering rule
- gallery order, membership order, and projection order are distinct and must not be conflated
The system must never rely on accidental storage order.
- list-card, detail-page, and other projections must be derived from declared projection contracts
- projection fields must be traceable back to canonical fields or declared derived rules
- projections may omit fields but must not invent undeclared semantic fields
- render surfaces must consume atlas projections, not reinterpret raw storage ad hoc
This keeps projection behavior canonical across products.
- relations must validate source kind, target kind, relation type, and cardinality
- memberships must validate ordering and composition constraints
- role-bearing relations must validate role semantics and edge metadata
- correspondences must validate mapping semantics independently from ordinary relations
No edge is valid merely because two ids exist.
- normalization rules must be declared, deterministic, and repeatable
- normalization must not depend on UI copy, locale guesswork, or heuristic intent detection
- repeated normalization of the same valid input must produce the same canonical representation
- canonical storage values must be derived mechanically from explicit contract rules only
This is the determinism gate.
- filterable fields must be declared explicitly by kind or projection contract
- sortable fields must be declared explicitly by kind or projection contract
- query behavior must not depend on undeclared incidental storage fields
- collection and library views must be defined by explicit contracts, not arbitrary frontend composition
This keeps query surfaces stable and portable.
- every lifecycle state must be declared explicitly
- transitions between lifecycle states must be declared explicitly
- visibility rules must compose with lifecycle rules deterministically
- publishing, archival, expiry, and revocation must be modeled as semantics, not frontend conventions
This prevents state machines from leaking into ad hoc application logic.
- storage projection must derive from contract data
- search projection must derive from contract data
- API shapes must derive from contract data
- admin/editor forms must derive from contract data
- relation and correspondence views must derive from contract data
If the same semantic rule has to be hand-maintained in multiple implementation layers, atlas has failed its purpose.
Any atlas feature or extension must satisfy all of the following:
- deterministic: the same contract and input produce the same canonical result
- canonical: one semantic rule has one declared source of truth
- mechanical: outputs are derived from explicit contract data, not heuristic application code
If a proposed feature breaks any of these, it should be rejected or redesigned.
k2atlas should be implemented as a contract compiler plus runtime.
The compiler loads CUE definitions and produces canonical internal representations.
The runtime uses those compiled contracts to validate entities, enforce relations, derive projections, and execute queries.
k2atlas should support runtime-loaded domain definitions.
This means new or updated CUE definitions can be introduced without producing a new application binary.
The application binary contains the atlas engine.
The domain model lives in versioned CUE definitions and is loaded dynamically at runtime.
This is a core design property, not a convenience feature.
- new definitions must be loadable without rebuilding the service binary
- new definitions must be activatable without redeploying the service binary
- activated definitions must behave as immutable runtime snapshots
- requests must execute against a single resolved snapshot, never a mixture of live mutable definitions
Runtime-loaded means:
- no new binary is required to roll out a new atlas kind, facet, relation, or projection contract
- definitions can be stored, validated, compiled, and activated by the running system
Runtime-loaded does not mean:
- raw CUE text is interpreted ad hoc on every request
- mutable definitions can drift during request execution
- canonicalization can be skipped
- validation and activation can be bypassed
The system still requires a compile-like activation step.
That step happens inside the running system and produces canonical runtime structures rather than a new executable artifact.
The correct model is:
- source contracts stored as immutable versioned CUE packages
- compiled runtime snapshots produced from those packages
- requests executed only against activated snapshots
This separates ontology evolution from binary deployment.
Runtime-loaded definitions should follow this activation pipeline:
- store a new immutable CUE package version
- load and validate the package
- compile it into canonical internal atlas structures
- validate cross-kind invariants and runtime readiness
- activate it atomically as a new snapshot
- materialize or rebuild any changed projections, views, or indexes
- route subsequent operations against the new snapshot
- every stored definition set must have an immutable version identifier
- a request must bind to exactly one activated definition version
- the system must be able to reject invalid versions without affecting the current active snapshot
- rollback to a previous valid snapshot must be possible without binary rollback
If a new definition changes query surfaces, projections, or relation semantics, atlas may need to trigger:
- projection rebuilds
- collection/view rematerialization
- index creation or migration in
k2db - compatibility validation for existing entities
These are activation-time or background-materialization concerns, not reasons to tie atlas evolution to binary releases.
Runtime-loaded definitions need a first-class registry model.
k2atlas should not treat definitions as anonymous text blobs.
Each stored definition set should have explicit registry metadata.
A definition package is the immutable source unit stored in the system.
Conceptual shape:
DefinitionPackage {
package_id: PackageId
version_id: VersionId
created_at: Timestamp
created_by: PrincipalId
source_format: "cue"
source_digest: Digest
source_bundle: CuePackage
status: DefinitionStatus
notes?: string
}
Suggested lifecycle states for stored definitions:
draftvalidatedcompiledactivesupersededrejectedretired
Only validated and compiled packages may become active.
The registry must support:
- immutable storage of source packages
- deterministic version addressing
- auditability of who created and activated which version
- lookup of current active snapshot
- lookup of historical active snapshots
- rollback to a previous compiled version
An activated atlas snapshot should be modeled explicitly.
Conceptual shape:
ActiveSnapshot {
snapshot_id: SnapshotId
package_id: PackageId
version_id: VersionId
activated_at: Timestamp
activated_by: PrincipalId
compiled_digest: Digest
runtime_state: SnapshotRuntimeState
}
Suggested runtime states:
warmingactivedraininginactivefailed
This allows atomic cutover without mixed-version request handling.
- exactly one snapshot is active per atlas domain scope unless multi-scope activation is declared explicitly
- a request binds to one snapshot at request start
- a snapshot may only become active after successful validation and compilation
- a failed activation must leave the prior snapshot intact
Runtime-loaded contracts require explicit compatibility rules.
Without them, atlas definitions will evolve faster than entity state and projections can safely follow.
Every new definition version should be classified as one of:
compatiblecompatible_with_rebuildmigration_requiredbreaking
compatible
- existing canonical entities remain valid
- no rebuild beyond normal activation is required
compatible_with_rebuild
- canonical entities remain valid
- projections, views, or indexes must be rebuilt
migration_required
- some canonical entities require deterministic migration before or during activation
breaking
- activation is rejected unless an explicit migration plan is supplied
At minimum, atlas should evaluate compatibility across:
- required field changes
- facet additions and removals
- relation cardinality changes
- target-kind changes
- lifecycle and visibility policy changes
- projection field changes
- filter and sort surface changes
- correspondence semantics changes
If migration is required:
- migration intent must be declared explicitly
- migration must be deterministic and repeatable
- migration must be traceable to the definition version transition
- migration may not rely on heuristic repair of invalid historical data
If deterministic migration is not possible, activation should be rejected.
Compatibility decisions must be based on a canonical structural diff, not on raw text comparison.
Atlas should compare compiled definition snapshots, not source formatting.
At minimum, a diff must detect changes in:
- kind declarations
- core field requirements
- facet requirements
- relation vocabularies
- membership vocabularies
- correspondence vocabularies
- target-kind constraints
- cardinality constraints
- lifecycle states and transitions
- visibility policies
- projection shapes
- filter surfaces
- sort surfaces
- normalization rules
Each detected change should be classified.
Suggested classes:
additiverestrictivesemanticprojection_onlyoperationalbreaking
additive
- new optional facet
- new optional projection field
- new optional relation type
- new filter or sort surface that does not invalidate existing entities
restrictive
- required field added
- cardinality tightened
- allowed target kinds narrowed
- visibility or lifecycle rules narrowed
semantic
- relation meaning changed
- correspondence type meaning changed
- normalization rules changed
- kind interpretation changed without obvious shape breakage
projection_only
- list-card or detail projection changed
- search or collection materialization changed
- no canonical entity meaning changed
operational
- index requirements changed
- materialization strategy changed
- rebuild policy changed
breaking
- previously valid canonical entities become invalid without deterministic migration
- previous query contracts become ambiguous or undefined
- identity or correspondence semantics become lossy or contradictory
The system should derive compatibility from the diff classes, not from a manually asserted label alone.
Recommended rules:
- only
additivechanges may be auto-activated with no rebuild projection_onlyandoperationalchanges require rebuild planning before activationrestrictivechanges require entity validation against existing canonical statesemanticchanges require explicit review and may require migration or dual-read compatibilitybreakingchanges must be rejected until a deterministic migration plan exists
The compatibility engine should emit a machine-readable report analogous to:
DefinitionDiff {
from_version: VersionId
to_version: VersionId
changes: [DiffChange]
compatibility_class: CompatibilityClass
requires_rebuild: bool
requires_migration: bool
blockers: [CompatibilityBlocker]
}
This report should drive activation decisions and materialization planning.
Atlas entity operations must bind explicitly to an active snapshot.
The system must never allow raw payloads to bypass snapshot-bound validation and normalization.
Every create or update operation should follow this sequence.
- bind request to active snapshot
S - authorize the operation via
k2rbac - resolve the target
kindunder snapshotS - validate raw payload against the compiled kind contract
- normalize payload deterministically
- validate relations, memberships, and correspondences against snapshot
S - persist the canonical entity and edge records with snapshot provenance
- emit materialization and lifecycle events
- update or enqueue derived projections and views
- return a response derived from snapshot
S
- a write must never validate against one snapshot and project against another
- canonical writes must record which snapshot normalized them
- relation and correspondence enforcement must happen before canonical commit
- failed projection rebuilds must not silently roll back canonical truth unless the operation is explicitly transactional across both layers
Every read operation should follow this sequence.
- bind request to active snapshot
Sor an explicitly requested compatible snapshot - authorize visibility and action semantics via
k2rbac - resolve the requested projection contract under snapshot
S - read canonical entity or materialized view data consistent with snapshot
S - apply declared query/filter/sort rules under snapshot
S - return a projection traceable to canonical fields and snapshot
S
- a read must never merge projections from multiple active snapshots implicitly
- query behavior must be evaluated under the snapshot that declares the query surface
- library and collection views must declare which snapshot produced them
- stale materializations must be rejected, rebuilt, or served only under explicit degraded-mode rules
Atlas should preserve provenance on canonical writes and derived outputs.
At minimum, an entity record should carry:
- canonical entity id
- kind id
- normalized snapshot version
- created at
- created by
- last updated at
- last updated by
- optional source lineage
This is necessary for migration, audit, and reproducibility.
When a new snapshot becomes active, existing entities may need one or more follow-up actions:
- no action
- reprojection only
- relation revalidation
- correspondence revalidation
- full entity revalidation
- deterministic migration
These actions should be derived from the compatibility report, not decided ad hoc in application code.
Atlas activation may change not only validation semantics but also read surfaces.
For that reason, projections and views should be treated as materialized derivatives of canonical entities plus the active snapshot.
At minimum, atlas may maintain:
- canonical entity records
- relation edge records
- membership edge records
- correspondence maps
- list-card projections
- detail projections
- collection or library views
- search/index projections
- every materialized output must record which snapshot produced it
- rebuild jobs must be restartable and idempotent
- partial rebuilds must not silently become the new truth
- read paths must either bind to a consistent snapshot or reject stale mixed materialization
The first atlas management surface should expose explicit operations for definition and snapshot control.
Suggested operations:
create_definition_packagevalidate_definition_packagecompile_definition_packageactivate_definition_packagerollback_snapshotdiff_definition_versionscheck_compatibilityplan_rebuildrun_materializationinspect_active_snapshot
These operations should be first-class atlas semantics, not hidden implementation details.
The first implementation should follow this pipeline.
- Load CUE packages.
- Validate package structure and vocabulary declarations.
- Compile kinds, facets, relations, memberships, and correspondences into canonical Rust structures.
- Validate cross-references and invariants.
- Produce compiled atlas definitions.
- Use compiled definitions at runtime for normalization, validation, projection derivation, and query planning.
The Rust side should be split into small deterministic subsystems.
loader
- loads atlas CUE packages
- resolves package roots and imports
- returns raw contract documents
compiler
- compiles raw contract documents into canonical Rust definitions
- resolves identifiers, references, and declared vocabularies
- rejects ambiguous or undeclared semantics
validator
- validates entity payloads against compiled kind contracts
- validates relations, memberships, and correspondences
- enforces cardinality, target-kind, and lifecycle rules
normalizer
- applies deterministic normalization rules
- emits canonical entity representation only
- never performs heuristic inference
projector
- derives storage, search, list-card, and detail projections
- guarantees traceability back to declared contracts
planner
- compiles query/filter/sort requests against declared query surfaces
- rejects undeclared query behavior
runtime
- orchestrates entity create/update/publish/archive operations
- enforces lifecycle, visibility, and relation constraints
- interacts with
k2db,k2rbac, andk2mx
materializer
- maintains derived views and collection projections
- updates relation and correspondence maps
- keeps read surfaces consistent with canonical state
The first compiler target should be a set of canonical internal types analogous to:
CompiledAtlas {
kinds: Map<KindId, CompiledKind>
facets: Map<FacetId, CompiledFacet>
relation_types: Map<RelationType, CompiledRelationType>
membership_types: Map<MembershipType, CompiledMembershipType>
correspondence_types: Map<CorrespondenceType, CompiledCorrespondenceType>
projections: Map<ProjectionId, CompiledProjection>
}
Each compiled type must be free of ambiguity.
By the time runtime execution starts, all references should already be resolved.
k2atlas should not own low-level storage primitives.
It should produce canonical records and derived projections for k2db to persist.
The persistence split should be:
- atlas owns semantic compilation, normalization, and projection derivation
k2dbowns persistence mechanics, indexing, and retrieval execution
k2atlas should integrate with the other k2 components as follows.
k2login
- identifies acting principals
k2rbac
- authorizes create, update, publish, archive, relate, and view operations
k2mx
- emits lifecycle and projection events
- receives import or sync triggers where applicable
k2db
- stores canonical entities, edges, correspondence maps, and derived read models
These are illustrative sketches only.
They show the shape atlas definitions should have, not finalized syntax.
package atlas
#EntityId: string
#KindId: string
#RelationType: string
#MembershipType: string
#CorrespondenceType: string
#LifecycleState: "draft" | "review" | "published" | "archived" | "expired" | "revoked"
#VisibilityPolicy: "private" | "authenticated" | "public" | "scheduled_public"
#LocalizedText: {
default_locale: string
values: [string]: string
}
#OrderingPolicy: {
weight?: int
pinned?: bool
freshness_window?: string
tie_breaker: "id" | "created_at" | "updated_at" | "title"
}
#AtlasEntity: {
id: #EntityId
kind: #KindId
title: #LocalizedText
summary?: #LocalizedText
visibility: #VisibilityPolicy
lifecycle: #LifecycleState
ordering?: #OrderingPolicy
facets: [string]: _
}package atlas
#Kinds: hotel: {
core: {
title: required: true
summary: required: true
media: required: false
taxonomy: required: false
locality: required: true
visibility: required: true
lifecycle: required: true
ordering: required: false
}
facets: {
hospitality: required: true
amenities: required: false
pricing: required: false
availability: required: false
contact: required: false
geo: required: false
seo: required: false
}
relations: {
located_in: {
targets: ["area", "city", "region"]
cardinality: "one_or_more"
}
has_variant: {
targets: ["room_type"]
cardinality: "many"
}
}
projections: {
list_card: true
detail_page: true
map_card: true
}
filters: {
locality: true
amenities: true
price_band: true
rating: true
}
}package atlas
#Kinds: book: {
facets: {
editorial: required: true
commerce: required: false
inventory: required: false
seo: required: false
}
relations: {
written_by: {
targets: ["author"]
cardinality: "one_or_more"
role_bearing: true
roles: ["lead_author", "co_author", "translator", "editor", "illustrator"]
}
}
correspondences: {
edition_of: true
supersedes: true
fulfills: true
public_variant_of: true
commercial_variant_of: true
}
}
#Kinds: series: {
memberships: {
contains: {
targets: ["book"]
ordered: true
cardinality: "many"
}
}
projections: {
list_card: true
series_page: true
}
}The safest first slice is small but complete.
It should implement:
- contract loading from CUE
- compilation into canonical Rust definitions
- one entity create/update normalization path
- relation validation
- ordered membership validation
- one list-card projection path
- one detail projection path
- deterministic query/filter/sort validation
Recommended initial kinds:
hotelroom_typeauthorbookseries
This set is enough to stress locality, variants, ordered composition, role-bearing edges, and typed correspondence without making the first implementation unbounded.
Relations must be first-class, typed, directional, and contract-defined.
Loose foreign keys are insufficient because they do not carry semantic meaning or constraints.
located_incontainsbelongs_tovariant_ofhas_variantnearservesrelated_torecommended_withpart_ofreferences
- hotel
located_inarea - area
located_incity - room type
variant_ofhotel - hotel
has_variantroom type - restaurant
nearbeach - excursion
recommended_withhotel - Phuket activity page
containslistings - beach club
belongs_tohospitality group
Each relation definition must declare:
typetarget_kindtarget_idcardinalityinverseconstraints- optional edge metadata
This allows definitions such as:
- a
room_typemust have exactly onevariant_ofedge to ahotel - a
hotelmay have manyhas_variantedges toroom_type - a
restaurantmay have one or morelocated_inedges to area-level localities
Some entities do not merely relate to other entities. They compose exact members in an exact order.
Examples:
- a book series contains exact books in an exact sequence
- a curated guide contains exact listings in editorial order
- a hotel may surface exact room types in a preferred order
Plain membership is insufficient for these cases.
k2atlas must support ordered composition edges with explicit sequence semantics.
An ordered membership edge should be able to carry:
target_idtarget_kindpositionlabelrequiredconstraints- optional inclusion metadata
This allows a series entity to mean more than "related books".
It means an ordered composition of exact members.
Some relations do not just connect entities. They express the role one entity plays with respect to another.
Examples:
- a book is
written_byan author - a book is
contributed_byan illustrator - a book is
translated_bya translator - a work is
edited_byan editor
The edge itself carries semantic meaning and may require metadata.
A role-bearing relation should support:
typeroletarget_idtarget_kindbilling_orderweightprimary- optional contribution metadata
This is necessary for publishing, commerce, hospitality, and other domains where the relationship itself has structure.
Not every surfaced thing should be treated as a canonical entity of the same class.
k2atlas must distinguish between:
- canonical entities
- curated collections
- derived views
- render projections
Examples:
- an author profile is a canonical entity
- a book is a canonical entity
- a series may be a canonical entity with ordered membership
- a library may be a scoped or curated view over entities rather than a single canonical entity
This distinction matters because views and projections often derive from canonical entities but do not own the same semantics or lifecycle.
k2atlas must support more than one notion of sameness.
Two records may refer to the same conceptual thing while remaining operationally distinct.
Examples:
- a purchased item may refer to edition 1 of a book
- a public catalog listing may refer to edition 2 of that same conceptual work
- both may need to be treated as related without being equal
This means atlas cannot rely on naive equality.
It must support typed, directional correspondence between entities.
At minimum, the system should distinguish:
- canonical entity identity
- semantic identity
- commercial identity
- public presentation identity
Initial correspondence and mapping types may include:
same_concept_asedition_ofsupersedespublic_variant_ofcommercial_variant_offulfillsentitles_access_to
These are not all symmetric.
Some are directional, some may be many-to-one, and some may represent partial equivalence rather than identity.
For example:
- purchased listing
Amayfulfillspublic listingA' - public listing
A'maypublic_variant_ofconceptual workW - commercial listing
Amaycommercial_variant_ofconceptual workW - edition 2 may
supersedesedition 1
The system must preserve these distinctions explicitly instead of collapsing them into a single equality relation.
Facets carry domain variation while the core remains stable.
Facets are not free-form bags of optional fields.
They are explicit contract modules with deterministic structure, validation, and semantics.
hospitalitycommerceprofilemobilityamenitiespricingavailabilitycontactseoeditorialgeoinventory
A hotel might compose:
hospitalityamenitiespricingavailabilitycontactgeoseo
A dating_profile might compose:
profilemediapreferencescontactvisibility
A car_rental might compose:
commercepricingavailabilitymobilitycontactgeo
The contract is not just for input validation.
From a kind definition, k2atlas should mechanically derive:
- canonical entity schema
- accepted facet set
- validation rules
- normalization rules
- lifecycle rules
- visibility rules
- allowed relations
- queryable and filterable fields
- sortable fields
- storage projection
- search projection
- list-card projection
- detail-page projection
- admin and editor form projection
- indexing requirements
- API contract
From relation and correspondence definitions, k2atlas should also derive:
- ordered membership projections
- contributor role projections
- identity and variant maps
- collection and library views
- edition and fulfillment navigation
If these outputs still have to be hand-authored repeatedly in multiple places, the system has failed its purpose.
A kind definition is not merely a list of fields.
It is a semantic contract that states:
- this entity is of kind
X - it uses these facets
- it requires these fields
- it permits these relations
- it exposes these filters
- it derives these projections
- it participates in these workflows
The contract describes the semantic behavior of an entity kind, not just its payload.
To keep k2atlas deterministic, canonical, and mechanically derivable:
- no heuristic inference from labels or UI copy
- no undeclared fields in canonical storage
- no relation without explicit type and target constraints
- no correspondence without explicit mapping semantics
- no facet without a declared schema
- no frontend-specific semantics in the core contract
- no page-builder concerns inside entity definitions
- no schema behavior that depends on application code guessing intent
k2atlas v0 should support:
- one canonical
AtlasEntity - typed
kinddefinitions loaded from CUE - typed facet composition
- typed directional relations
- ordered membership relations
- role-bearing contributor relations
- typed identity correspondence
- lifecycle and visibility policies
- derived list and detail projections
- deterministic query, filter, and sort surfaces
That is enough to prove the architecture without trying to solve every downstream problem in the first iteration.
k2atlas is the missing semantic layer between raw storage and rendered pages.
It solves the repeated complexity of discoverable entities once, generically, so frontends can consume already-typed, already-related, already-curated data instead of rebuilding semantics ad hoc.