Skip to content

Generated reference. This page mirrors Code/Ownerships/README.md, this module's source-of-truth documentation (Standards/02_DOCUMENTATION_STANDARDS.md §1). Edit it there, not here -- this file is regenerated on every docs build and any local edit is silently overwritten.

Ownership

Purpose. One generic claim over an entity — who owns it, and who else may access it — applying uniformly to doors, vehicles, and any other ownable world object, per Legacy/04_ENTITIES_DOORS_PROPERTY.md and 08_DATA_MODEL.md §5. This module has no idea what a door is — that is World's job; it only tracks the claim.

Responsibilities. - Ownership, OwnerRef, OwnerKind, AccessGrant, AccessLevel, OwnableId — the typed replacement for the legacy _Owner table (Legacy/04_ENTITIES_DOORS_PROPERTY.md §1) and its three-different-runtime-types-in-one-field encoding (D-16). - IOwnershipService / OwnershipStoreLoadOrCreateAsync (an entity with no claim yet loads as unowned, not missing), AssignOwnerAsync (also captures the OwnerDisplayName snapshot at assignment time — see §5's note on why this isn't a live lookup), HasAccess (now takes an AccessLevel, hierarchical — see §5), GrantAccessAsync (writes AccessList, added by ADR-0009). - Persistence under ownership/{entityId} (08_DATA_MODEL.md §8).

Not responsible for. - Resolving OwnerKind.Team/.Gang membership in HasAccess — the Jobs module (the group/gang/team hierarchy) does not exist yet, so there is no membership to check against. A Team- or Gang-owned entity is accessible today only through an explicit per-character AccessGrant, never through kind-matching against a job the caller happens to hold. This is a real gap, not a design decision — resolve it once Jobs lands (ROADMAP.md Milestone 7). - What kind of entity is ownable, or what owning one lets you do (open a door, drive a vehicle) — that is each entity's own module (World, eventually Vehicles). Ownership answers "who," never "what does that mean here." - Revoking a grant — GrantAccessAsync (ADR-0009) replaces a character's existing grant with a new one, but there is still no way to remove a character from AccessList entirely. Not built because no consumer needs it yet; see "Future improvements."

Dependencies. Core (IServiceRegistry, IServiceResolver, IPersistenceBackend, ISchemaRegistry, IEventBus, IGameLog), Character (CharacterId, used by AccessGrant and to construct a Character-kind OwnerRef).

Public API. - IOwnershipServiceLoadOrCreateAsync(OwnableId), AssignOwnerAsync(OwnableId, OwnerRef, string ownerDisplayName), HasAccess(Ownership, CharacterId, AccessLevel), GrantAccessAsync(OwnableId, CharacterId, AccessLevel).

Events published. None yet — deferred until a consumer (a scoreboard, a "your access was revoked" notification) exists, following Inventory's README's and Economy's README's identical deferral.

Persistence. OwnershipDocument { EntityId, Owner, OwnerDisplayName, AccessList } under ownership/{entityId}, schema version 1.

Future improvements. - Team/Gang membership resolution in HasAccess, once Jobs exists. - A RevokeAccessAsync to remove a character from AccessList entirely, once a consumer needs it — GrantAccessAsync (ADR-0009) only ever replaces or adds, never removes. - A Manage level (letting a non-owner grant others access) once a real consumer needs it — Use/Passenger/Drive (ADR-0009) are ordered by vehicle privilege, not general-purpose.