From 03991c383a7feb38d270deb89f6cf6bf349edc26 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 15 Jul 2026 00:51:54 +0100 Subject: [PATCH] Clarify Ymir Box3D authority boundary --- AGENTS.md | 10 ++- README.md | 41 +++++++++--- docs/aetheria-cutover.md | 6 +- docs/architecture.md | 62 ++++++++++++++----- docs/box3d-parity.md | 11 ++-- src/Ymir.Core/Ymir.Core.csproj | 2 +- .../YmirServicePublicationDocument.cs | 30 ++++----- src/ymir-daemon/Program.cs | 2 +- src/ymir-daemon/ymir-daemon.csproj | 1 + .../Ymir.Tests/YmirServicePublicationTests.cs | 11 +++- 10 files changed, 126 insertions(+), 50 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ac7c0f9..bbb8913 100644 --- a/AGENTS.md +++ b/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. diff --git a/README.md b/README.md index d7c1434..5947864 100644 --- a/README.md +++ b/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 diff --git a/docs/aetheria-cutover.md b/docs/aetheria-cutover.md index 66512f5..4d32e47 100644 --- a/docs/aetheria-cutover.md +++ b/docs/aetheria-cutover.md @@ -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. diff --git a/docs/architecture.md b/docs/architecture.md index a4e021b..011ff3e 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -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 diff --git a/docs/box3d-parity.md b/docs/box3d-parity.md index d9e7790..40a9628 100644 --- a/docs/box3d-parity.md +++ b/docs/box3d-parity.md @@ -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. diff --git a/src/Ymir.Core/Ymir.Core.csproj b/src/Ymir.Core/Ymir.Core.csproj index 241aa28..7d75bd3 100644 --- a/src/Ymir.Core/Ymir.Core.csproj +++ b/src/Ymir.Core/Ymir.Core.csproj @@ -18,7 +18,7 @@ enable Ymir.Core Ymir.Core - GameCult physics/world substrate engine built on CultMath. + GameCult physics cutover contracts and parity boundary for pinned Box3D. GameCult diff --git a/src/Ymir.Core/YmirServicePublicationDocument.cs b/src/Ymir.Core/YmirServicePublicationDocument.cs index 0573799..21bbece 100644 --- a/src/Ymir.Core/YmirServicePublicationDocument.cs +++ b/src/Ymir.Core/YmirServicePublicationDocument.cs @@ -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) }; diff --git a/src/ymir-daemon/Program.cs b/src/ymir-daemon/Program.cs index 88b4b49..5f6968e 100644 --- a/src/ymir-daemon/Program.cs +++ b/src/ymir-daemon/Program.cs @@ -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. diff --git a/src/ymir-daemon/ymir-daemon.csproj b/src/ymir-daemon/ymir-daemon.csproj index 7cd479b..9a233ea 100644 --- a/src/ymir-daemon/ymir-daemon.csproj +++ b/src/ymir-daemon/ymir-daemon.csproj @@ -11,6 +11,7 @@ enable enable ymir-daemon + Ymir cutover CLI; the retained Box3D daemon session is not active yet. diff --git a/tests/Ymir.Tests/YmirServicePublicationTests.cs b/tests/Ymir.Tests/YmirServicePublicationTests.cs index a6a4d93..45b0f53 100644 --- a/tests/Ymir.Tests/YmirServicePublicationTests.cs +++ b/tests/Ymir.Tests/YmirServicePublicationTests.cs @@ -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); }