Ymir/docs/architecture.md
Meta Vens 21e7c43777 Remove the Eve surface from Ymir.Core (parked at parked/ymir-eve-surface)
Eve is deprecated; per thing2:ruling:eve-dashboards-quarantined the surface builders, EveSurfaceDocument publication, GameCult.Eve.Surface reference and EveRoot are gone. YmirOperatorStateDocument and its publication stay.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 20:02:38 +02:00

237 lines
11 KiB
Markdown

# Ymir Architecture
## Objective
Expose Box3D as authoritative, typed, persistent GameCult physics without
leaking an alpha native API into products, clients, or durable state.
Ymir's target is a stable embedded wrapper around retained Box3D worlds, not an
independent physics-engine research project. Box3D supplies the physics mind.
Ymir supplies the memory, nerves, names, and session boundary. The same
boundary may optionally be hosted as a standalone daemon.
## Target Owner
A long-lived Box3D `b3World` owns the physical decision: given the current
world plus commands for a fixed step, what transforms, velocities, overlaps,
casts, and contact transitions are true.
Ymir owns the enclosing session and contract:
- pin and build the accepted Box3D release;
- map stable GameCult ids to transient Box3D handles;
- accept typed body, shape, filter, force, torque, field, query, and step
commands;
- project Box3D outputs into typed, deterministically ordered Ymir facts;
- reconstruct sessions from CultCache checkpoints;
- return typed state, contacts, queries, and receipts to an embedding product;
- when running standalone, publish Ymir's own physics provider and operator
surfaces through CultMesh;
- supervise world lifetime, failure, replay, and observability.
## Deployment Boundary
For Aetheria, Ymir is an embedded library. Aetheria owns the outer daemon,
gameplay session, fixed tick, product commands and receipts, asset catalog, and
advertised Eve/CultMesh surface. Generic Eve clients connect directly to the
Aetheria daemon. They never import Ymir internals and do not route gameplay
through a standalone Ymir or discovery service.
A standalone Ymir daemon is an optional hosting mode for physics tooling and
other products. It hosts the same Ymir session primitive; it is not an
Aetheria relay and cannot own a shadow copy of Aetheria's world.
## Current Body
The runtime solver cut is complete: Box3D is the only integrator, collision
engine, broadphase, query-geometry implementation, and contact source in the
committed Ymir path. The public `YmirSimulator.Step` compatibility API creates
an isolated internal session for one complete snapshot, projects its output,
and disposes it. Public circle overlap and cast APIs invoke Box3D geometry over
caller-supplied bodies.
The retained native session now has a public in-process `YmirSession` port with
explicit spawn, remove, teleport, velocity, configuration, force, torque,
step, and disposal operations. It emits revisioned receipts and typed
Begin/Hit/End facts with stable Ymir identities. Ordinary retained steps do not
accept complete body snapshots.
The embedded retained-session library has replay-backed reconstruction,
durable command receipts, incremental journal-suffix capture, and bounded
resume descriptors. Aetheria stores these in a second daemon-private CultCache:
immutable chunks are flushed first, immutable per-frame resumes second, and the
public Aetheria frame last. The public frame is the only commit marker. Orphaned
private records cannot advance gameplay truth, and restart fails closed once
the persistence capability has been activated. Complete replay history is not
product state and never rides in public client frames. The current CLI still
has no named session registry or CultMesh command lowerings; its CultCache
output remains a regenerated diagnostic projection.
## Target Inputs
- stable body and shape definitions
- fixed time step and explicit substep count
- transient forces, torques, impulses, and target transforms
- collision filters and material definitions
- overlap, ray, and shape-cast queries
- product-owned selections such as which pickup ids a tractor may affect
Aetheria chooses physical intent and gameplay eligibility. Box3D decides
geometry membership and contact. Ymir carries the typed handoff.
## Target Outputs
- body transforms and linear/angular velocities
- begin, end, and hit contact facts with stable Ymir ids
- overlap and cast results sorted by distance and stable id
- step receipts and replay/checkpoint provenance
- provider-owned operator and debug projections
Box3D callback order is not a public contract. Ymir may sort facts, but it may
not alter their membership or invent missing contacts.
## Derived State
- Box3D world, body, shape, contact, and joint handles are transient session
state derived from stable Ymir definitions.
- CultCache checkpoints are reconstruction inputs and publication records; they
are not a second live solver.
- SoA body documents are transport and inspection projections over the live
session.
- Unity GameObjects and Electron objects are render state only.
- Aetheria damage, loot, capacity, faction, and scoring consequences are
derived from Ymir facts plus Aetheria policy.
## Dimensional Compatibility
The fossil Aetheria simulation uses a two-dimensional gameplay plane. During
cutover, Ymir maps that plane into Box3D X/Z with translation on Y locked and
rotation constrained to the plane normal. This is an explicit compatibility
projection. It does not make Ymir a second 2D physics engine.
Sphere friction and inertia are not identical to planar disk behavior. Any
mechanic that depends on that difference must be witnessed against the fossil
and then expressed through Box3D configuration, not repaired by a parallel
solver.
## Forbidden Writers
- managed integration, impulse resolution, collision geometry, or broadphase
code in Ymir;
- persisted force or torque replayed as if it were continuing authority;
- Aetheria rectangle, capsule, overlap, or contact tests deciding gameplay
physics;
- Unity collision callbacks deciding hits, destruction, or pickup collection;
- renderer transforms pushing hidden corrections into the world;
- transport endpoints or dashboards owning world state;
- Box3D opaque ids stored as durable GameCult identity.
## Target Shared Paths
Direct player commands, agent commands, programmatic spawns, server ticks,
imports, reconnects, replay, and checkpoint recovery will enter the same Ymir
session primitive for their named world. Today, DTO compatibility methods
lower into an isolated Box3D session; they may not run an alternate step or
infer retained identity from a body list.
Session identity must be explicit. A process-wide simulator object, zone index,
or repeated stable body id is not enough to join two calls to the same world.
Aetheria owns run and zone lifetime and creates, retains, and disposes the
corresponding embedded Ymir session. Projectile sweep
and stationary mine proximity integration can use Ymir's revision-checked
retained-session circle-cast and overlap queries. They observe the current
stable-id body projection; they do not invent a contact episode or mutate the
Box3D world.
Radial gravity and tractor attraction are typed force-generation inputs. They
are applied to Box3D before stepping. Pickup collection remains an Aetheria
transaction triggered exactly once by a Ymir/Box3D contact fact.
## Native Boundary
`extern/box3d` pins the accepted upstream source. `native/Ymir.Box3D` owns a
small stable C ABI facade. Managed Ymir code binds only to that facade; it does
not scatter hundreds of direct P/Invokes across the daemon.
The native facade must remain boring:
- caller-owned blittable buffers;
- explicit version and precision facts;
- no GameCult gameplay policy;
- no JSON state boundary;
- no public exposure of Box3D internal handles;
- first-class RID packaging before production consumers depend on it.
## Target Persistence Contract
Canonical deterministic replay starts from the same initial definitions and
creation order, then applies the complete command stream under the pinned
Box3D build and accepted runtime configuration.
A checkpoint restart is a different promise. Its schema must contain enough
typed definitions and state to reconstruct an equivalent Box3D world: stable
ids, 3D transforms, linear and angular velocity,
body/shape/material/filter definitions, session tuning, and provenance. Box3D
does not expose every internal solver cache, so arbitrary mid-world checkpoint
restart is tested against named numeric state tolerances rather than claimed as
bit-identical continuation. Contact membership, ordering, and exactly-once
lifecycle identity are binary contracts, not tolerance checks. Authoritative
contact facts resume only after canonical history has been replayed through the
checkpoint tick; a checkpoint alone cannot emit gameplay contact facts.
`gamecult.ymir.session_checkpoint.replay.v1` implements that promise. It stores
the initial definitions, complete typed command journal, logical session
generation, command digest, body-generation counter, world verification
projection, active contact-episode verification records, and pinned runtime
fingerprint. Restore replays into a new Box3D world with outward publication
suppressed, then compares the reconstructed boundary exactly before returning a
live session. The bounded binary codec rejects incompatible, corrupt, or
trailing data and checksums the complete encoded payload. ABI v5 validates the
exact pinned native build id, not merely Box3D's public version. Native Box3D
identities never enter the checkpoint.
`gamecult.ymir.world_state.v2` appends Box3D body type, bullet,
field-participation, and collision filter arrays to the v1 layout. The v1 and
v0 readers are explicit migration paths; keys are not reassigned. Torque is
transient command state and is intentionally absent. Version 2 is a
compatibility world snapshot, not a complete retained-session
checkpoint: it does not preserve full shape, material, filter, session tuning,
provenance, or warm contact state.
Transient forces and torques are commands, not durable body state. Derived
mass and inertia are published only when useful for inspection. Old checkpoint
versions must migrate explicitly or fail closed; they may not silently decode
under a reassigned MessagePack layout.
## Cut Line
The managed integrator and circle impulse solver have been deleted from the
runtime path. Any uncommitted `YmirQueryPrimitives` or `YmirSpatialIndex` work
is obsolete and must not be annexed. The retained-session cut continues until
Box3D-backed sessions prove:
1. fixed-step body state projection;
2. begin/end/hit contact lifecycle;
3. overlap and shape-cast lowering;
4. continuous collision event timing and same-step Box3D cast witnesses;
5. transient force and torque application;
6. checkpoint reconstruction and replay (implemented; journal compaction and
long-running storage remain operational work);
7. Aetheria gravity, tractor, pickup, and payload smokes.
There is no managed fallback after that cut. A native load or compatibility
failure fails closed and reports the missing capability.
## Required Verification
- Box3D parity tests record released upstream law at the native boundary.
- Ymir differential tests compare public projections with the same Box3D
session facts.
- Negative source checks prove custom solver and spatial-index authorities are
absent after cutover.
- Aetheria smokes prove gravity, tractor attraction, contact-gated pickup
collection/rejection, physical payload hits, and restart continuation through
the retained contract. Destruction loot remains Aetheria gameplay state
gated by Ymir contact facts where collection occurs.
- Released-client witnesses prove generic Eve clients only observe Ymir and
Aetheria provider contracts, never native implementation details.