Clarify Ymir Box3D authority boundary
This commit is contained in:
parent
658db6c986
commit
03991c383a
10 changed files with 126 additions and 50 deletions
10
AGENTS.md
10
AGENTS.md
|
|
@ -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.
|
||||
|
|
|
|||
41
README.md
41
README.md
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue