|
|
|
@@ -0,0 +1,232 @@
|
|
|
|
|
# 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
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
|
|
## Related decisions and references
|
|
|
|
|
|
|
|
|
|
- ADR: [`../adr/0002-domain-identity-namespaces.md`](../adr/0002-domain-identity-namespaces.md)
|
|
|
|
|
- Architecture: [`../ARCHITECTURE.md`](../ARCHITECTURE.md)
|
|
|
|
|
- Foundation plan: [`../../targets/roadmap/01-foundation-and-data.md`](../../targets/roadmap/01-foundation-and-data.md)
|