Cory Policht
← All references
REF · ADR-SCP-002-ENGINE-AS-ADAPTER · ADR

Adr Scp 002 Engine As Adapter

source: Spatial-Cognition-Platform/ADR/ADR-SCP-002-Engine-As-Adapter-Unity-Client.mdscrubbed extract

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 test loop; 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 and link.xml preservation.

Negative / Risks

  • Dual compile can drift (Unity C# version vs SDK csproj) — pinned LangVersion in 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.

  • [[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