ADR-001: Caller-owned fixed-capacity world

Date: 2026-07-18

Status: Accepted

Context

The architecture for v0.1.0 left the world memory and lifecycle strategy open in section 9.2. Epic E02 requires one owner for authoritative state, no hidden global mutable world, no dynamic allocation inside Pet Core, and a compile-time maximum for every collection.

Three candidate strategies were available: caller-owned storage, Core-allocated opaque state, and caller-supplied storage passed as a buffer and size.

Decision

PetWorld is a complete public structure. The caller declares the storage and chooses where it lives, and pet_world_init writes into that storage.

Every bounded collection has a capacity macro, so the size of a world is fixed when the library is compiled. Pet Core never allocates a world, never frees one, and retains no pointer to one.

The pet is stored inline in its world rather than referenced, so its lifetime is exactly the lifetime of the world that owns it.

Consequences

Several worlds may exist independently because nothing is shared between them. A world can live on the stack, in static storage, or inside memory the caller obtained elsewhere, which suits both hosted and embedded environments.

Callers can see the field layout. The header states that fields are visible for sizing and placement rather than as a stable interface, and later PBIs add operations that read state without exposing mutable pointers into nested storage.

Changing a capacity macro changes the size of PetWorld, so it is a recompilation for every caller. The v0.1.0 measurements on Linux x86-64 are 48 bytes for PetWorld, 40 bytes for PetEntity, and 8 bytes for PetWorldConfig, with no temporary Core storage beyond the parameters of an operation. These figures are the measurement taken when this decision was accepted. Later work adds persistent fields, so the current measurement lives in the storage section of the architecture. The world clock added by ADR-002 is the first such change.

A world declared without an initialiser holds indeterminate storage. PET_WORLD_INITIALISED gives initialisation a recognisable marker rather than a boolean flag that cannot be distinguished from unwritten memory.

Alternatives considered

Core-allocated opaque state. Hides the layout and keeps the header stable, but requires an allocator or an arena inside Pet Core. E02 and SPEC-NFR-002 exclude this.

Caller-supplied buffer and size. Keeps the layout opaque without allocating, but adds an alignment and size contract to every operation and needs runtime validation that a fixed structure gets from the compiler. The extra contract has no benefit while one world holds one pet.

References