Scrubbed extract of
Spatial-Cognition-Platform/ADR/ADR-SCP-002-Engine-As-Adapter-Unity-Client.md— cited by the Chronicle (06-extraction-and-divergence, 07-the-long-march). Redactions: phone / service detail / secrets / clearance / personal / internal hosts.
type: project project: Spatial-Cognition-Platform status: accepted created: 2026-08-27 tags:
- adr
- architecture
- unity
- hexagonal
ADR-SCP-002: Unity is the engine; the engine is an adapter
Status: Accepted Date: 2026-08-27 Deciders: Solo (Cory) Context Project: [[Spatial-Cognition-Platform]]
Context
The visual surface is Unity (given). The founding concept’s core stance is “the 3D graph is a view, never the system.” If domain logic leaks into MonoBehaviours, the platform becomes a Unity app with opinions instead of a world model with a Unity view — and the around-the-clock local-model workforce (ADR-SCP-007) can only safely own code it can verify headless.
Decision
The client repo is spatial-cognition-xr (Gitea homelab/spatial-cognition-xr), containing a Unity 6 project whose domain core is engine-free C#, with Unity strictly as an adapter layer. Same ports-and-adapters discipline as repo-intel and wezterm-voice.
Assembly structure
Engine-free core (asmdefs with noEngineReferences: true, netstandard2.1-compatible C#):
Scp.Domain— Entity, Assertion, Artifact, AgentWork, Provenance, Workspace model; invariants.Scp.Contracts— wire DTOs mirroring the JSON Schemas + serialization (ADR-SCP-004).Scp.Projection— deterministic layout/view computation: pure functions(snapshot, viewRules, seed) → placements. Golden-file testable.Scp.App— use-cases and ports:ISnapshotSource,IReasoningStore,IWorkspaceStore,IClock,ILog.
Unity-side adapters (may reference the engine and Meta SDK):
Scp.Unity.View— prefab/rendering of nodes, edges, panels, beams.Scp.Unity.Interaction— Meta Interaction SDK bindings → App-layer commands.Scp.Unity.Net— HTTP snapshot fetch, file IO adapters.Scp.Unity.Boot— hand-rolled composition root (no DI framework for POC).
Single source tree, two build systems
Core source lives under unity/SpatialCognition/Assets/Scp/Core/** and is compiled twice: by Unity (asmdefs) and by a standalone core/Scp.Core.sln whose csprojs include the same sources via <Compile Include> globs. dotnet test runs the xunit suites with no Unity installed — this is verification rung 1 (ADR-SCP-007). CI compiles the linked solution with no UnityEngine reference, mechanically proving the core is engine-free.
Repo layout
spatial-cognition-xr/
├── contracts/ # JSON Schemas + versioned fixtures (ADR-SCP-004)
├── core/ # Scp.Core.sln + tests (source-links Assets/Scp/Core)
├── unity/SpatialCognition/
├── tools/snapshot-exporter/
└── .gitea/workflows/ # rung-1 CI: dotnet test + schema validation
Consequences
Positive
- Local models own domain/contracts/projection work with a fast
dotnet testloop; Unity is never required to verify their output. - Engine swap (or a parallel desktop 3D client, per the concept’s risk table) costs only new adapters.
- JSON serialization is Newtonsoft Json.NET on both sides (Unity’s blessed
com.unity.nuget.newtonsoft-json), IL2CPP-safe with explicit converters andlink.xmlpreservation.
Negative / Risks
- Dual compile can drift (Unity C# version vs SDK csproj) — pinned
LangVersionin both; CI catches drift. - No DI container means manual wiring in
Scp.Unity.Boot; acceptable at POC scale, revisit if the composition root exceeds ~200 lines. - IL2CPP AOT stripping can eat reflection-based serialization — fixtures round-trip in a device build as part of slice S1’s definition of done.
Alternatives Considered
Alternative 1 — Unreal Engine
Rejected because: C++ iteration speed and no engine-free .NET core would exclude the qwen workforce from most of the codebase; no existing C# skill reuse; passthrough tooling on Quest is weaker than Meta’s Unity path.
Alternative 2 — WebXR (three.js/babylon)
Rejected because: Quest browser passthrough (immersive-ar) support and hand-interaction fidelity lag native; performance ceiling for dense graphs; diverges from the .NET/C# estate.
Alternative 3 — Godot
Rejected because: OpenXR passthrough on Quest is functional but Meta feature parity (Interaction SDK, simulator, capture tooling) is far behind; POC timeline cannot absorb that gap.
Alternative 4 — Unity DOTS/ECS for the graph
Rejected because: POC graph is hundreds of nodes, not millions; DOTS complicates the engine-free core seam. Revisit only if profiling shows GameObject rendering as the bottleneck (gate in ADR-SCP-008).
Alternative 5 — DI framework (VContainer/Zenject)
Rejected because: one composition root, one scene, POC scale — a framework adds concepts for agents to misuse. Revisit at multi-scene/multi-workspace stage.
Related
- [[ADR-SCP-004-Contract-First-Projection-Wire-Format]] — the seam the core is built around
- [[ADR-SCP-007-Executor-Tiers-And-Verification-Ladder]] — why engine-free matters operationally