Clarify Ymir Box3D authority boundary

This commit is contained in:
Meta Vens 2026-07-15 00:51:54 +01:00
commit 03991c383a
10 changed files with 126 additions and 50 deletions

View file

@ -19,8 +19,8 @@ Architecture constraints:
- Do not reimplement Box3D integration, collision geometry, broadphase,
queries, solver behavior, contact lifecycle, or numeric tolerances.
Physics edge cases follow the pinned Box3D release and executable parity
tests.
Physics edge cases follow the pinned Box3D release. Executable parity tests
witness selected released behaviors; they are not a second specification.
- `Ymir.Core` owns typed contracts, stable-id projection, session commands,
deterministic ordering, persistence reconstruction, and publication. The
native Ymir wrapper owns Box3D ABI isolation. Daemon, Unity, and future Rust
@ -34,6 +34,12 @@ Architecture constraints:
publication.
- Keep adapters boring. A Unity adapter may submit commands, receive snapshots,
and render them; it must not silently repair or override Ymir state.
- During cutover, provider advertisements and operator state must describe the
running implementation. Target Box3D/CultMesh capabilities are not live
capabilities until their production paths exist.
- Aetheria embeds Ymir. Eve clients connect directly to Aetheria's advertised
CultMesh provider; standalone Ymir and rendezvous services are not in the
Aetheria gameplay path.
- Add tests at the layer where the invariant lives. State invariants belong in
`Ymir.Core`; daemon route shape belongs in daemon smokes; Unity visual timing
bugs need Unity-side probes.

View file

@ -1,24 +1,31 @@
# Ymir
Ymir is the GameCult Box3D wrapper and authoritative physics daemon for
Aetheria and future world-bearing projects. The name means **Not Invented
Here**. We are taking the hint.
Ymir is the GameCult library and service boundary around a pinned Box3D
release, being cut over into Aetheria's authoritative embedded physics
substrate. The name means **Not Invented Here**. We are taking the hint.
Box3D owns physics algorithms. Ymir owns the service boundary that makes those
algorithms usable as durable, typed GameCult world truth. Unity, renderers, and
game products consume Ymir state and contact facts; they do not become physics
authorities.
## Ownership
The Box3D parity facade currently witnesses a bounded released-behavior slice.
The production command path still runs the transitional managed solver and is
not Box3D-authoritative until one retained Box3D session embedded in the
Aetheria daemon owns every step, query, and contact fact.
## Target Ownership
- Box3D owns rigid-body integration, collision geometry, broadphase, solver
behavior, continuous collision, overlap and cast semantics, contact
lifecycle, force and torque lifetime, tolerances, and deterministic step
behavior for identical recorded inputs.
lifecycle, force and torque lifetime, tolerances, and step behavior for an
identical creation order and command stream under the accepted build and
runtime configuration.
- Ymir owns the pinned Box3D version, stable GameCult entity ids, native ABI
isolation, long-lived world sessions, typed commands and facts,
deterministic result ordering, checkpoint reconstruction, CultCache state,
CultMesh publication, and daemon lifecycle.
deterministic result ordering, checkpoint reconstruction, and the embedded
session boundary. Its optional standalone service owns only its own
publication and lifecycle.
- Aetheria owns gameplay policy and supplies typed physical intent: bodies,
fields, tractor targets, forces, projectiles, filters, and the gameplay
consequences of Ymir contact facts.
@ -30,6 +37,24 @@ authorities.
Box3D opaque handles are process-local derived state. They are never durable
entity ids and never cross the public contract boundary.
Ymir does not promise bit-identical continuation from an arbitrary mid-world
snapshot. Replay starts from canonical creation order plus the complete command
stream. Checkpoints may accelerate numeric state recovery within named
tolerances, but authoritative contact lifecycle facts resume only after that
canonical history has been replayed through the checkpoint tick.
## Aetheria Deployment Boundary
Aetheria embeds the Ymir library and native Box3D wrapper in its own daemon.
The Aetheria daemon owns gameplay ticks, world policy, player sessions,
commands, receipts, assets, and the Eve/CultMesh provider advertisement.
Generic Eve clients connect directly to Aetheria; they do not connect through
Ymir or a rendezvous service.
A future standalone Ymir daemon may expose the same physics contract for
tooling or other products. It is not an intermediary in Aetheria's gameplay
path and must never become a competing copy of Aetheria world truth.
## Current Cutover State
Box3D v0.1.0 is pinned at commit

View file

@ -17,7 +17,11 @@ Unity physics use.
- A projectile with a Unity collider disabled still travels and hits through
Ymir.
- A Unity `OnCollisionEnter` callback cannot apply damage independently.
- Reloading or replaying the same Ymir world produces the same contact order.
- Replaying from the same canonical creation order and command stream under the
accepted Box3D build produces the same ordered Ymir facts.
- Restarting from a checkpoint matches named numeric state tolerances. It emits
no authoritative gameplay contact facts until canonical history has replayed
through the checkpoint tick and restored exact contact lifecycle identity.
- Mid-flight visible projectile position matches the Ymir snapshot within a
named tolerance.

View file

@ -5,11 +5,12 @@
Expose Box3D as authoritative, typed, persistent GameCult physics without
leaking an alpha native API into products, clients, or durable state.
Ymir is a wrapper and daemon, not an independent physics-engine research
project. Box3D supplies the physics mind. Ymir supplies the memory, nerves,
names, and service boundary.
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.
## Owner
## 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,
@ -23,11 +24,32 @@ Ymir owns the enclosing session and contract:
commands;
- project Box3D outputs into typed, deterministically ordered Ymir facts;
- reconstruct sessions from CultCache checkpoints;
- publish provider, operator, command, receipt, and Eve surfaces through
CultMesh;
- 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.
## Inputs
## 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 a second 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 Mechanism
The native facade currently exists only as a bounded parity oracle. Each world
step witness creates and destroys a short-lived Box3D world. Production
`ymir-daemon` commands still call the transitional managed `YmirSimulator`; no
retained Box3D world or live CultMesh provider session exists yet. The owner,
dataflow, and persistence sections below describe the cutover target.
## Target Inputs
- stable body and shape definitions
- fixed time step and explicit substep count
@ -39,7 +61,7 @@ Ymir owns the enclosing session and contract:
Aetheria chooses physical intent and gameplay eligibility. Box3D decides
geometry membership and contact. Ymir carries the typed handoff.
## Outputs
## Target Outputs
- body transforms and linear/angular velocities
- begin, end, and hit contact facts with stable Ymir ids
@ -87,7 +109,7 @@ solver.
- transport endpoints or dashboards owning world state;
- Box3D opaque ids stored as durable GameCult identity.
## Shared Paths
## Target Shared Paths
Direct player commands, agent commands, programmatic spawns, server ticks,
imports, reconnects, replay, and checkpoint recovery all enter one Ymir world
@ -113,12 +135,22 @@ The native facade must remain boring:
- no public exposure of Box3D internal handles;
- first-class RID packaging before production consumers depend on it.
## Persistence
## Target Persistence Contract
The canonical checkpoint schema must contain enough typed definitions and
state to reconstruct the accepted Box3D world: stable ids, 3D transforms,
linear and angular velocity, body/shape/material/filter definitions, session
tuning, and provenance.
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.
Transient forces and torques are commands, not durable body state. Derived
mass and inertia are published only when useful for inspection. Old checkpoint
@ -141,7 +173,7 @@ deleted when retained Box3D sessions prove:
There is no managed fallback after that cut. A native load or compatibility
failure fails closed and reports the missing capability.
## Verification
## Required Verification
- Box3D parity tests record released upstream law at the native boundary.
- Ymir differential tests compare public projections with the same Box3D

View file

@ -51,8 +51,9 @@ is retained in the pinned submodule.
## Cut Line
The current managed collision formulas are transitional. They may exist only
while differential tests prove compatibility. The remaining parity slice
covers retained world sessions, end-contact lifecycle, continuous collision,
and replay. Once those facts are projected through a stable Ymir native port,
the managed solver, query geometry, and spatial indexes are deleted rather
than retained as fallback authority.
until differential coverage and production-session witnesses prove the public
cutover contract. Missing production coverage includes retained world
sessions, end/hit contact lifecycle, continuous collision, replay, checkpoint
restart, and RID packaging. Once those facts are projected through a stable
Ymir native port, the managed solver, query geometry, and spatial indexes are
deleted rather than retained as fallback authority.

View file

@ -18,7 +18,7 @@
<Nullable>enable</Nullable>
<RootNamespace>Ymir.Core</RootNamespace>
<AssemblyName>Ymir.Core</AssemblyName>
<Description>GameCult physics/world substrate engine built on CultMath.</Description>
<Description>GameCult physics cutover contracts and parity boundary for pinned Box3D.</Description>
<Authors>GameCult</Authors>
</PropertyGroup>

View file

@ -17,7 +17,7 @@ public sealed class YmirProviderAdvertisementDocument
public string Title { get; set; } = "Ymir Physics";
[Key(2)]
public string Description { get; set; } = "GameCult authoritative Box3D session wrapper and physics daemon.";
public string Description { get; set; } = "GameCult cutover CLI and service-record publisher for the planned Box3D wrapper.";
[Key(3)]
public string[] Owns { get; set; } = [];
@ -41,13 +41,13 @@ public sealed class YmirOperatorStateDocument
public string ProviderId { get; set; } = "ymir.physics";
[Key(1)]
public string Status { get; set; } = "mvp";
public string Status { get; set; } = "box3d-cutover";
[Key(2)]
public string StateOwner { get; set; } = "Ymir world sessions and typed GameCult projections";
public string StateOwner { get; set; } = "Stateless managed step/query DTOs and derived service records";
[Key(3)]
public string NumericSubstrate { get; set; } = "Box3D v0.1.0 (C17)";
public string NumericSubstrate { get; set; } = "Active: CultMath managed solver; target oracle: pinned Box3D v0.1.0 (C17)";
[Key(4)]
public string BatchKernel { get; set; } = "";
@ -81,20 +81,22 @@ public static class YmirServicePublication
{
ProviderId = "ymir.physics",
Title = "Ymir Physics",
Description = "GameCult authoritative Box3D session wrapper and physics daemon.",
Description = "GameCult cutover CLI and service-record publisher for the planned Box3D wrapper.",
Owns =
[
"authoritative physics session lifecycle",
"stable GameCult id to Box3D handle projection",
"typed physics commands and facts",
"stateless managed step and query request handling",
"stable GameCult physics identity",
"typed physics request and result DTOs",
"deterministic result ordering",
"CultCache checkpoint reconstruction",
"CultMesh and Eve service publication"
"CultCache world and service record emission",
"Eve operator surface projection"
],
DoesNotOwn =
[
"physics algorithm invention",
"Box3D solver and collision semantics",
"retained Box3D production sessions during cutover",
"CultMesh provider sessions or discovery during cutover",
"Unity scene truth",
"rendering",
"gameplay damage policy",
@ -107,10 +109,10 @@ public static class YmirServicePublication
public static YmirOperatorStateDocument OperatorState(DateTimeOffset now) => new()
{
ProviderId = "ymir.physics",
Status = "mvp",
StateOwner = "Ymir world sessions and typed GameCult projections",
NumericSubstrate = "Box3D v0.1.0 (C17)",
BatchKernel = "Box3D native solver; Ymir does not own physics algorithms",
Status = "box3d-cutover",
StateOwner = "Stateless managed step/query DTOs and derived service records",
NumericSubstrate = "Active: CultMath managed solver; target oracle: pinned Box3D v0.1.0 (C17)",
BatchKernel = "Transitional managed solver; no retained Box3D session",
Persistence = "CultCache gamecult.ymir.world_state.v0 legacy checkpoint during Box3D cutover",
UpdatedAtUtc = FormatUtc(now)
};

View file

@ -115,7 +115,7 @@ internal static class Program
private static void PrintHelp()
{
Console.WriteLine("""
Ymir physics daemon
Ymir physics cutover CLI
Commands:
publish-service [--path .ymir/service.cc] Regenerate the derived service publication.

View file

@ -11,6 +11,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AssemblyName>ymir-daemon</AssemblyName>
<Description>Ymir cutover CLI; the retained Box3D daemon session is not active yet.</Description>
</PropertyGroup>
</Project>

View file

@ -16,10 +16,15 @@ public sealed class YmirServicePublicationTests
var diagnostics = YmirServicePublication.OperatorState(now);
Assert.Contains("Box3D", advertisement.Description, StringComparison.Ordinal);
Assert.Contains("authoritative physics session lifecycle", advertisement.Owns);
Assert.Contains("stateless managed step and query request handling", advertisement.Owns);
Assert.Contains("Box3D solver and collision semantics", advertisement.DoesNotOwn);
Assert.Equal("Box3D v0.1.0 (C17)", diagnostics.NumericSubstrate);
Assert.Contains("does not own physics algorithms", diagnostics.BatchKernel, StringComparison.Ordinal);
Assert.Contains("retained Box3D production sessions during cutover", advertisement.DoesNotOwn);
Assert.Contains("CultMesh provider sessions or discovery during cutover", advertisement.DoesNotOwn);
Assert.DoesNotContain("daemon", advertisement.Description, StringComparison.OrdinalIgnoreCase);
Assert.DoesNotContain(advertisement.Owns, claim => claim.Contains("session", StringComparison.OrdinalIgnoreCase));
Assert.Equal("box3d-cutover", diagnostics.Status);
Assert.StartsWith("Active: CultMath managed solver", diagnostics.NumericSubstrate, StringComparison.Ordinal);
Assert.Contains("no retained Box3D session", diagnostics.BatchKernel, StringComparison.Ordinal);
Assert.Contains("world_state.v0", diagnostics.Persistence, StringComparison.Ordinal);
}