Files
open-wc/docs/modules/domain-identities.md
T
sindoring c1dc07c705 feat(M01): add typed domain identities
Work-Package: M01-FND-DOMAIN-IDENTITIES-001

Agent: sindo-main-codex
2026-07-13 16:11:00 +04:00

11 KiB

Domain Identities

Metadata

Field Value
Status Implemented
Target/work package M01-FND-DOMAIN-IDENTITIES-001
Owners Foundation/domain
Last verified Worktree work/sindo-main-codex/m01-domain-identities, 2026-07-13
Profiles/capabilities All profiles; identity contract version 1

Purpose

Provide non-interchangeable, scene-free identity values for authored content, runtime entities, WoW wire objects and namespaced server entries. Each value states its lifetime and serialization rules instead of exposing a generic id.

Non-goals

  • Allocating, reserving or globally registering IDs.
  • Parsing packet bytes or server database rows.
  • Mapping GUID high types or server entries to gameplay object kinds.
  • Defining Content Project, snapshot or replay schemas.
  • Replacing future typed map/spell/item/quest/display/sound IDs.

Context and boundaries

flowchart LR
    Authoring[Content Project allocator] --> ContentId[ContentId]
    Session[Entity registry] --> EntityId[EntityId]
    Wire[Build 12340 packet adapter] --> WowGuid[WowGuid]
    Server[Core snapshot adapter] --> ServerEntry[ServerEntryId]
    ContentId --> Mapping[Explicit identity mapping records]
    EntityId --> Mapping
    WowGuid --> Mapping
    ServerEntry --> Mapping
    Mapping --> Consumers[Gameplay / network / authoring consumers]
    Raw[Raw int or string] -. forbidden across boundary .-> Consumers

Allowed dependencies:

  • GDScript scalar/string operations and RefCounted lifetime;
  • callers in content, gameplay, network and server adapter layers.

Forbidden dependencies:

  • Node, Resource, SceneTree, renderer and UI state;
  • packet buffers, SQL connections or database table implementations;
  • implicit conversion between identity namespaces;
  • random/global allocation inside the value objects.

Public API

Symbol Kind Purpose Thread/lifetime Errors
ContentId Immutable value Stable authored identity as canonical lowercase UUID text Any thread; persisted content lifetime is_valid() reports malformed shape
ContentId.equals Pure method Value equality across references Call duration Null compares false
ContentId.to_key Pure method Canonical serialization/dictionary key Stable across schema lifetime Caller must validate first
EntityId Immutable value Positive session-local runtime sequence One runtime session is_valid() rejects zero/negative
EntityId.equals Pure method Equality within an explicitly shared session Call duration Cross-session comparison is a caller error
EntityId.to_debug_key Pure method Non-persistent diagnostic label Session/log lifetime Must not be serialized as content
WowGuid Immutable value Opaque unsigned high/low wire words Packet/replay/entity mapping lifetime has_valid_word_ranges() reports overflow
WowGuid.is_empty Pure method Detect all-zero wire sentinel Call duration Does not assign semantic meaning
WowGuid.to_hex_string Pure method Sixteen-digit diagnostic/replay key Wire/replay lifetime Caller validates ranges first
ServerEntryId Immutable value Adapter/table namespace plus positive entry Snapshot/deployment mapping lifetime is_valid() rejects missing namespace/non-positive entry
ServerEntryId.to_key Pure method Namespaced mapping key Snapshot/schema lifetime Caller validates first

Inputs and outputs

Direction Contract/data Producer Consumer Ownership Thread/lifetime
Input UUID text Future Content Project allocator/parser ContentId Copied normalized string Build/content lifetime
Input Session sequence Future entity registry EntityId Copied integer One runtime session
Input Two unsigned 32-bit words Future build-12340 packet codec WowGuid Copied integers Packet/replay/entity lifetime
Input Namespace and numeric entry Future core snapshot adapter ServerEntryId Copied normalized string/integer Snapshot/deployment lifetime
Output Validation/equality/key results Identity values Adapters/registries/schemas Returned scalar/string Call duration

Side effects:

  • none;
  • no allocation registry, random generation, file/cache write, packet read, database query, scene mutation or logging.

Data flow

flowchart TD
    ContentSource[Authored document] -->|UUID text| ContentId
    ServerRow[Backend table row] -->|adapter + table + entry| ServerEntryId
    Packet[World packet] -->|high/low wire words| WowGuid
    Registry[Session entity allocator] -->|positive sequence| EntityId
    ServerEntryId --> DeployMap[Explicit deployment mapping]
    ContentId --> DeployMap
    WowGuid --> RuntimeMap[Explicit runtime mapping]
    EntityId --> RuntimeMap
    DeployMap --> Snapshot[Versioned snapshot/change set]
    RuntimeMap --> WorldState[Session world state]

Lifecycle/state

stateDiagram-v2
    state ContentIdentity {
        [*] --> Parsed
        Parsed --> Persisted: valid ContentId
        Persisted --> Referenced
    }
    state RuntimeIdentity {
        [*] --> Allocated
        Allocated --> Active
        Active --> Released: session owner removes entity
        Released --> [*]
    }
    state ExternalIdentity {
        [*] --> Observed
        Observed --> Mapped: WowGuid or ServerEntryId
        Mapped --> Stale: disconnect or snapshot replacement
        Stale --> [*]
    }

The values themselves are stateless and immutable. Allocation, release, mapping and stale-state ownership belong to future registries/adapters.

Main sequence

Identity construction and validation are synchronous. An external adapter reads its format, constructs the matching value, validates it, then publishes an explicit mapping or typed domain event. No value object performs I/O or retries.

Ownership, threading and resources

  • Values own only copied strings/integers and are caller-owned RefCounted references.
  • Public methods do not mutate values or shared state and are worker-safe.
  • Content/session/wire/server mapping records are owned by their future layer, not by these values.
  • No Node, RID, file, socket, database, lock or cache resource is acquired.

Errors, cancellation and recovery

Failure Detection Behavior Diagnostic Recovery
Malformed ContentId is_valid() Invalid value remains inspectable Source field/path supplied by parser Regenerate or repair authored ID
Invalid EntityId sequence is_valid() Registry must reject publication Session/correlation context Fix allocator/session mapping
GUID word overflow has_valid_word_ranges() Codec must reject packet/replay value Packet offset/opcode context Reject malformed input; do not truncate
Empty GUID is_empty() Preserved as protocol sentinel Adapter decides whether field permits empty Apply opcode/field-specific rule
Missing server namespace/entry is_valid() Snapshot adapter rejects mapping Backend/table/row context Correct adapter schema mapping
Unknown/stale mapping Registry/snapshot lookup No implicit numeric fallback Typed IDs in diagnostic Refresh snapshot/session or reject event

There is no cancellation inside constant-time value operations.

Configuration and capabilities

Setting/capability Default Profile Runtime mutable Effect
Identity contract version 1 All No Four separate namespaces and validation rules
ContentId text form Lowercase 8-4-4-4-12 UUID Authoring/runtime/tools No Stable persisted key
GUID decomposition Opaque two-word storage wotlk_335a_build_12340 No Prevents unverified high-type assumptions

Persistence, cache and migration

  • ContentId.uuid_text is the only stable persisted identity introduced here.
  • Containing schemas must store their own schema version and duplicate/reference policy.
  • EntityId must never be persisted across sessions.
  • WowGuid may appear in versioned packet replays as explicit high/low words or the exact sixteen-digit hex form; a replay schema owns that choice.
  • ServerEntryId may appear in snapshots only with both namespace and entry.
  • This package is additive and migrates no existing data or cache.

Diagnostics and observability

  • Stable diagnostics use ContentId.to_key, WowGuid.to_hex_string and ServerEntryId.to_key.
  • Runtime diagnostics may use EntityId.to_debug_key with a session correlation ID.
  • Production metrics/logging belong to registries and adapters; values emit none.

Verification

  • Contract test: src/tools/verify_domain_identities.gd.
  • Fixtures cover UUID normalization/malformed shape, positive/zero session IDs, maximum/overflow GUID words, zero GUID and cross-table server entry collisions.
  • Dependency gate confirms no Node/Resource/Vector3 exposure.
  • Fidelity boundary: GUID bit meaning remains unclaimed until build-12340 packet fixtures.
  • Performance: constant-time integer checks and a bounded 36-character UUID scan.

Extension points

  • Content Project allocator and duplicate/reference validation.
  • Session-owned entity registry and explicit WowGuid ↔ EntityId mappings.
  • Backend capability adapters that define server entry namespaces.
  • Separate typed map/spell/item/quest/display/sound values.
  • Fixture-backed build-12340 GUID high-type decoding in the protocol layer.

Capability status

Capability Status Evidence Gap/next step
Stable authored ContentId Implemented contract UUID normalization/validation fixtures Allocator and schema arrive with Content Project
Session-local EntityId Implemented contract Positive/zero/equality fixtures Registry lifecycle arrives with gameplay world state
Lossless opaque WowGuid Implemented contract Full unsigned words and hex fixture Packet codec/high-type semantics need build-12340 fixtures
Namespaced ServerEntryId Implemented contract Cross-table collision fixture Backend namespace capability mapping arrives with server adapters
Cross-namespace mappings Planned Architecture/ADR boundary Implement only in owning registries/adapters

Known gaps and risks

  • No allocator or duplicate registry exists yet.
  • GDScript == compares references; consumers must use domain equals methods or canonical keys until a registry owns keying.
  • UUID shape validation deliberately does not enforce generation version/variant.
  • Server namespace vocabulary is adapter-owned and not yet centrally catalogued.
  • GUID high-type/object-kind semantics remain unverified rather than guessed.

Source map

Path Responsibility
src/domain/identity/content_id.gd Stable canonical UUID content identity
src/domain/identity/entity_id.gd Session-local runtime identity
src/domain/identity/wow_guid.gd Opaque unsigned WoW wire identity
src/domain/identity/server_entry_id.gd Namespaced backend entry identity
src/tools/verify_domain_identities.gd Headless value/boundary regression
docs/adr/0002-domain-identity-namespaces.md Normative namespace/lifetime decision