Session artifact · final

Game Architecture

An architecture document full with details about core systems, implementation patterns and much more..

Document
TestGame Production-Chain Strategy PoC
Created
2 August 2026
Updated
2 August 2026

Game Architecture

Executive Summary

TestGame uses Unity 6.5 Update (6000.5.6f1) for a local Windows desktop strategy PoC.

Authoritative gameplay lives in a Unity-independent, session-scoped C# domain model. Unity and uGUI act as explicit engine and presentation adapters, while a thin Bootstrap assembly composes the application.

Key architectural decisions:

  • Commands validate completely and commit atomically before publishing events.
  • ScriptableObjects are immutable authoring inputs converted through a strict definition-to-session boundary.
  • Production uses exact destination reservations and full restoration on cancel.
  • Persistent snapshots and selective typed changes make player-visible causality part of correctness.
  • Explicit state machines, typed IDs, injected registries, and focused factories prevent incompatible implementations.
  • Edit Mode domain tests carry most rule coverage; focused Play Mode tests verify Unity integration and complete journeys.

Project structure: Hybrid organization with four runtime boundaries and 15 mapped core systems.

Implementation patterns: Three novel and four standard patterns define transactions, feedback, configuration conversion, communication, creation, state transitions, and data access.

Ready for: Implementation-readiness validation and story implementation.

Document Status

This architecture document was completed through the GDS Architecture Workflow.

Steps Completed: 9 of 9 (Complete)


Project Context

Game Overview

TestGame is a real-time fantasy strategy proof of concept about building small, readable production chains whose outputs create immediate and measurable combat or Quest effects.

The intended experience progresses through comprehension, anticipation, agency, and payoff. The project is a bounded learning experiment for its solo creator, not a vertical slice or commercial release candidate.

Technical Scope

Engine: Unity
Platform: Local-only Windows desktop, keyboard and mouse
Reference Layout: 1600×900
Genre: Real-time fantasy strategy / production sandbox
Project Level: Medium complexity, tightly bounded scope
Session Model: Fresh, non-persistent single-player session
Networking: None

Core Systems

System Complexity Architectural significance
World interaction and camera Medium Selection, box selection, control groups, contextual commands, bounded camera, and world/UI focus must coexist cleanly.
Building placement Medium Pad validation, route preservation, placement previews, and immutable placement require deterministic validation.
Mythical Storage Medium Shared authoritative resource state feeds concurrent production chains and must provide exact accounting.
Production jobs High Independent timers, one-job-per-building rules, committed inputs, cancellation refunds, and visible background progress form a transactional state system.
Recipes and crafting High Crafting crosses storage, job, and inventory boundaries and must commit or reject changes atomically.
Inventory reservation High Ten slots support reservation, cancellation, upgrades, equipment, eligibility, and full-capacity blockers without item loss or duplication.
Equipment and effects High Permanent and temporary percentage-based HP modifiers must stack, round, expire, and clamp current HP consistently.
Unit commands and navigation Medium Five controllable units require selection, movement, attacks, collision avoidance, and navigation around placed buildings.
Combat and recovery High Deterministic attacks, pursuit limits, defeat, encounter reset, delayed player recovery, and persistent session progression interact closely.
Deer and Monster AI Medium Separate bounded behavior profiles need predictable acquisition, pursuit, return, fleeing, and unstuck behavior.
Morale Flag High Deployment validation, spatial membership, visible duration, non-stacking effects, and cleanup require coordinated world and stat state.
Hero skills and Scrolls Medium Drop, learn, equip, target-preview, execute, and cooldown states must remain distinct and observable.
Quests and session counters Medium Retroactive progress, independent acceptance, exactly-once updates, and persistent completion require event-driven tracking.
Persistent HUD and feedback High Storage, timers, selection, Quests, blockers, remedies, effects, and causal values must remain legible across world interactions.
Baseline evaluation Medium Repeatable sessions, tuning records, performance evidence, and end-to-end checks must support an evidence-based continue/stop decision.

Technical Requirements

  • Sustain an average of at least 60 FPS and a 1% low of at least 55 FPS during the specified ten-minute reference workload on Tim’s development PC.
  • Support the 1600×900 reference layout and window resizing without hiding Storage, selection context, active Quest progress, or active job timers.
  • Complete three consecutive end-to-end sessions without blockers, corrupted state, or external inspection or mutation through development tools.
  • Keep gameplay deterministic enough that exact production and combat consequences can be explained from the game surface.
  • Treat invalid actions as side-effect-free operations that identify both the blocker and its remedy.
  • Keep all tuning values lightweight and externally configurable without changing player-facing rules.
  • Preserve full visual comprehension without requiring audio, hover-only information, networking, accounts, telemetry, or persistence.
  • Communicate state through text or iconography as well as color.
  • Record performance configuration and tuning changes for repeatable evaluation.

Complexity Drivers

Transactional state across systems

Production and crafting operations span Storage, Building availability, timers, Inventory reservations, and Quest progress. Start, cancel, and completion paths must be atomic to prevent duplication, loss, or contradictory presentation.

Concurrent timed activity

Several Buildings can work independently while the player commands units and fights. Timers and results must continue correctly when contextual panels close.

Unified effect calculation

Equipment and temporary Flag modifiers affect current and maximum HP using specific independent rounding, stacking, removal, and clamping rules. One authoritative calculation path is required.

Event ordering and exactly-once consequences

Monster defeats drive loot and Quest progress; crafting completion drives Inventory delivery and Quest progress. Events must be processed exactly once, including when Quests are accepted after qualifying actions.

World state and UI state synchronization

The game’s success depends on causal readability. Every authoritative gameplay transition must produce a corresponding visible state without making UI objects the owners of gameplay rules.

Recoverable combat state

Player defeat, full-party defeat, Monster reset, delayed respawn, persistent equipment, retained progression, and temporary-effect cleanup must resolve without deadlock.

Runtime navigation constraints

Buildings are placed during play yet cannot obstruct required routes. Navigation and placement validation must share a reliable representation of traversability.

Novel Architectural Elements

  • Production as an observable proof system: combat and Quests are validation surfaces for economic choices, so observability is part of game correctness rather than presentation polish.
  • Reservation-preserving item upgrade: crafting T2 Armor consumes T1 Armor, reuses its slot reservation, and must restore that exact item and slot on cancellation.
  • Baseline-versus-extension boundary: architecture must permit one bounded experiment to be added without prematurely introducing systems excluded from the Baseline.

Technical Risks

  • Resource or item duplication/loss across cancellation and completion paths.
  • Divergence between authoritative game state and persistent HUD presentation.
  • Incorrect HP after overlapping equipment and Flag effects are added or removed.
  • Duplicate loot, Quest credit, completion, or recovery events.
  • Units becoming stuck during acquire, pursue, return, or runtime obstacle changes.
  • UI scaling hiding critical information or making causal feedback unreadable.
  • Scene objects or UI panels becoming tightly coupled owners of domain state, making later tuning and extensions expensive.
  • Scope creep toward logistics, content breadth, or production-grade frameworks that do not serve the Baseline experiment.
  • Performance measurements becoming unreliable if reference hardware, build profile, workload, and profiling method are not recorded.

Engine & Framework

Selected Engine

Unity 6.5 Update — 6000.5.6f1

Rationale: The repository already contains an initialized Unity project using this editor version. Unity is appropriate for the Windows-only 3D strategy PoC, providing mature rendering, input, navigation, physics, UI, profiling, and testing support. Keeping the installed Update release avoids an unnecessary downgrade while the project remains an exploratory PoC.

The editor version is pinned by ProjectSettings/ProjectVersion.txt. Version changes require an explicit architecture decision and a verified project backup.

Project Initialization

Use the existing Unity project in TestGame/. It is already configured as a Universal Render Pipeline project. Do not import an opinionated RTS starter framework: its additional economy, combat, selection, and AI assumptions would conflict with the deliberately bounded Baseline.

No initialization command is required because the Universal 3D project already exists and its editor/package versions are pinned in the repository.

Engine-Provided Architecture

The following choices are PROVIDED BY THE EXISTING UNIVERSAL 3D PROJECT:

Component Solution Notes
Rendering Universal Render Pipeline 17.5.0 Appropriate for readable stylized 3D and the target performance envelope.
Physics Unity 3D Physics Use colliders, overlap queries, raycasts, and triggers selectively; deterministic domain rules must not depend on unstable collision ordering.
Input Unity Input System 1.20.0 Provides action maps, pointer/keyboard input, control groups, and UI/world input separation.
Navigation AI Navigation 2.0.14 Provides NavMesh pathfinding; runtime placement and route validation remain explicit architecture decisions.
Audio Built-in Unity Audio Optional in Baseline; no gameplay information may depend on sound.
Scene Management Unity scenes and prefabs Exact bootstrap and gameplay-scene composition remain to be defined.
UI Foundation Unity UI packages The presentation framework and state-binding pattern remain to be selected.
Build System Unity Windows player build Local Windows desktop is the only Baseline target.
Testing Unity Test Framework 1.7.0 Supports Edit Mode and Play Mode validation.
Profiling Unity Profiler and performance test tooling Reference hardware, build profile, workload, and measurement method must accompany results.

Development Tooling

MCP for Unity

Use the open-source CoplayDev MCP for Unity as the preferred editor bridge.

Purpose:

  • Inspect scenes, assets, GameObjects, components, and editor state.
  • Create and modify editor objects through explicit Unity operations.
  • Read compiler and Console output.
  • Run tests and automate repetitive editor workflows.
  • Validate scene wiring that cannot be proven through source inspection alone.

Installation type: Unity Package Manager plus a local Python-based MCP server.

Package URL:

https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity#main

MCP access is development-only, remains local, and must not become a runtime or build dependency. Editor-changing operations require deliberate authorization.

Context7

Use Context7 for current, version-aware Unity and package documentation.

Context7 is documentation tooling only. It neither controls Unity nor becomes a game dependency. Prefer official Unity documentation returned through Context7 when resolving API or package-version questions.

Remaining Architectural Decisions

The following decisions must be made explicitly:

  • Gameplay state ownership and dependency direction
  • Assembly Definition boundaries
  • ScriptableObject configuration versus mutable runtime state
  • Commands, events, and presentation update flow
  • Production and crafting transaction semantics
  • Inventory reservation and cancellation semantics
  • Stat modifier stacking, rounding, removal, and HP clamping
  • Unit, Monster, and Deer state machines
  • Runtime placement and navigation-route validation
  • Quest counters and exactly-once event processing
  • UI framework and state-binding approach
  • Simulation clock, timer behavior, and pause semantics
  • Scene/bootstrap composition
  • Testing boundaries, diagnostics, and performance evidence

Architectural Decisions

Decision Summary

# Category Decision Version Rationale
1 State ownership Plain C# domain model with Unity adapters — Keeps authoritative rules independently testable and separates engine concerns.
2 Game definitions Immutable ScriptableObject definitions with plain C# runtime state Unity 6000.5.6f1 Provides Inspector tuning without mutable shared-asset state.
3 Mutation flow Synchronous command handlers with post-commit domain events — Ensures invalid actions are side-effect free and transactions remain atomic.
4 Time Central session clock with system-owned accumulators — Makes jobs, cooldowns, effects, and recovery testable without lockstep complexity.
5 Production transactions Validate all preconditions, then commit atomically — Prevents resource/item loss and supports exact-slot restoration.
6 Stats Recalculate derived HP from base values and active modifiers — Prevents drift and preserves exact stacking, rounding, and clamping rules.
7 Code organization Domain, Unity, Presentation, and thin Bootstrap assemblies plus test assemblies — Enforces dependency direction with modest project overhead.
8 Runtime UI uGUI + TextMesh Pro with passive views and presenters uGUI 2.5.0 One mature framework supports both HUD and world-anchored feedback.
9 Unit and AI behavior Explicit finite-state machines with NavMesh adapters AI Navigation 2.0.14 Makes transitions, fallback behavior, and recovery observable and testable.
10 Placement/navigation Authored pads with baked navigation guarantees AI Navigation 2.0.14 Eliminates runtime rebuilding and route-blocking ambiguity.
11 Scene structure Single gameplay scene with explicit composition root — Provides controlled session lifecycle without unnecessary loading infrastructure.
12 Quests/progress Authoritative counters with idempotent event processing — Supports retroactive acceptance and exactly-once consequences.
13 Asset loading Direct references, prefabs, and ScriptableObject catalogs — Fits the fixed Baseline content without Addressables complexity.
14 Testing Edit Mode domain tests plus focused Play Mode integration tests Test Framework 1.7.0 Balances fast rule verification with engine integration confidence.

Technology versions were verified against the existing project and current documentation on 2026-08-02.

State Management

GameSession is the session-scoped authoritative domain root. It owns resources, jobs, Inventory, unit state, effects, progress counters, and Quests.

The domain consists of plain C# and does not reference UnityEngine. Unity components adapt input, physics, navigation, frame updates, and presentation to domain commands and snapshots. No globally mutable singleton or service locator owns gameplay rules.

Small explicit finite-state machines govern player units, Monsters, Deer, and encounter recovery. State transitions have guards and defined fallbacks.

Configuration and Runtime Data

ScriptableObjects hold immutable authored definitions:

  • Recipes and resource outputs
  • Items and eligibility
  • Units and first-playable tuning
  • Skills and cooldowns
  • Quests
  • Global balance/timing values

Session startup validates these assets and creates mutable plain C# runtime state. Runtime systems never mutate ScriptableObject assets. Definitions use stable IDs independent of asset names and paths.

Validation detects duplicate IDs, invalid references, negative quantities, unsupported eligibility, and incomplete scene wiring.

Command and Event Flow

Only command handlers mutate authoritative state:

Input/UI → Command → Validate → Atomic commit → Immutable domain events
                                               ├─ Progress and Quests
                                               ├─ Presentation
                                               └─ Diagnostics

Failures contain a blocker and remedy, change no state, and publish no success event. Events describe facts that have already committed and cannot veto or rewrite the originating transaction.

Event routing is session-scoped with explicit registration. UI renders snapshots of current authoritative state rather than attempting to reconstruct state from event history.

Timing Model

A Unity adapter advances the session using scaled Time.deltaTime. Domain code never reads Unity’s static time APIs.

Each timed system owns explicit accumulated or remaining time. Large frame deltas are consumed safely, including multiple resource-generation intervals. Jobs, cooldowns, Flags, and recoveries complete once.

Closing panels does not affect simulation. Pausing advances gameplay by zero; presentation may use unscaled time for appropriate visual behavior. Tests advance a fake clock by exact durations.

Deterministic replay, rollback, and lockstep simulation are not required.

Production and Inventory Transactions

Job start validates every precondition before mutation:

  • Building availability and Recipe support
  • Exact committed inputs
  • Item eligibility
  • Destination capacity
  • Specific Inventory reservation when required

Processing commits resources without reserving Inventory. Final Crafting reserves one exact slot before consuming inputs. Cancellation refunds exact committed inputs and releases that reservation. Completion converts the reserved slot directly to occupied.

T2 Armor consumes one eligible, unequipped T1 Armor and reserves the same slot. Cancellation restores that exact item instance to that exact slot.

Jobs have stable IDs, and start, completion, and cancellation paths are idempotent. Inventory ownership follows Empty → Reserved → Occupied; focus, equipment, and eligibility are orthogonal attributes.

Stats and Effects

Base maximum HP is immutable during a session. Equipment and temporary effects contribute modifiers identified by stable source IDs.

Each percentage modifier is independently calculated from base HP using round-half-up, then summed. Sword, Armor, and one Flag modifier may coexist; a second Flag modifier is rejected.

Derived stats are recalculated from base values and active modifiers rather than incrementally patched. Adding an HP item increases current and maximum HP by the derived increase. Removal recalculates maximum HP and clamps current HP to the new maximum, never below one for a living unit.

Defeat, recovery, equipment, and Flag expiration all use this same stat service.

Assembly Boundaries

TestGame.Domain
    Plain C# state, rules, commands, events, and definition interfaces

TestGame.Unity
    MonoBehaviours, ScriptableObjects, input, physics, navigation,
    scene composition, and domain adapters
    → references TestGame.Domain

TestGame.Presentation
    HUD, panels, presenters, and world feedback
    → references TestGame.Domain and narrow Unity-facing interfaces

TestGame.Bootstrap
    SceneCompositionRoot and top-level application composition only
    → references TestGame.Domain, TestGame.Unity, and TestGame.Presentation

TestGame.Tests.EditMode
    → primarily tests TestGame.Domain

TestGame.Tests.PlayMode
    → tests adapters, scene wiring, navigation, and integrated journeys

TestGame.Domain never references Unity or Presentation. Presentation cannot mutate state directly; it submits commands through a narrow session interface.

UI Architecture

Use uGUI and TextMesh Pro for Baseline runtime UI.

Views are passive MonoBehaviours. Presenters read immutable snapshots, format player-facing values, populate views, and submit commands from controls. Structured command failures supply exact blockers and remedies.

Persistent HUD regions use layout groups, anchors, and CanvasScaler. World feedback uses world-space canvases or camera-projected screen elements. Essential information never exists only on hover or through color.

Transient elements such as damage values are pooled only when profiling demonstrates a meaningful allocation issue. UI Toolkit may be used for future Editor tooling but is not a second Baseline runtime framework.

Unit and AI Architecture

Player units use:

Idle → Moving → Attacking → Defeated → Recovering → Idle

Monsters use:

Idle → Acquiring → Pursuing → Attacking → Returning → Idle
                             └──────────→ Defeated

Deer use:

Idle → Fleeing → Idle
              └→ Defeated

Domain state owns health, eligibility, defeat, recovery, and encounter rules. Unity adapters own NavMeshAgent operations and report arrival or path failure.

Player commands replace existing movement or attack intent. Invalid targets, pursuit limits, unreachable paths, and recovery always lead to defined states. Nearby-target acquisition uses bounded physics queries at a controlled cadence, not global per-frame searches.

Placement and Navigation

Placement uses authored BuildingPad objects. Each pad defines accepted Building types, footprint bounds, and a fixed transform.

Buildings snap to pads positioned outside required navigation corridors. A pad transitions once from available to occupied. Validation checks availability, eligibility, footprint fit, and references before confirmation.

The sandbox uses a baked NavMesh. Runtime rebuilding is excluded. Play Mode tests verify representative routes between the starting area, production zone, Deer zone, and both Monster encounters after every Building is placed.

Scene Composition

BaselineSandbox.unity is the only required scene:

BaselineSandbox
├─ SceneCompositionRoot
├─ Environment
├─ Navigation
├─ PlacementPads
├─ UnitsAndEncounters
├─ WorldFeedback
└─ ScreenUI

The composition root validates references, loads definitions, constructs GameSession, and connects adapters and presenters in an explicit order. The session is disposed on scene unload, and every load creates fresh state.

Gameplay managers do not use DontDestroyOnLoad. A bootstrap/loading scene is deferred until a real second scene or asynchronous initialization requirement exists.

Quest and Progress Architecture

SessionProgress owns qualifying counters such as Monster defeats and completed T2 Armor. The originating defeat or Craft-completion transaction updates its counter atomically before publishing. Stable transaction/event IDs prevent duplicate application.

Quest acceptance initializes from the relevant session counter. Active Quests derive progress from those counters rather than maintaining competing values. Quest state only transitions Available → Active → Complete, with completion emitted once.

Loot eligibility belongs to each Monster’s authoritative state. A designated Monster can produce its configured Scroll once. Popups consume committed events; persistent trackers render Quest snapshots.

Assets and Loading

The scene and composition root use explicit serialized references to prefabs and definition catalogs. Definition assets may directly reference their icons, prefabs, and static dependencies.

Do not use Resources.Load, string-based asset paths, or Addressables in the Baseline. Missing dependencies fail through Editor validation or session startup.

The small fixed roster and world objects are instantiated normally. Addressables may be reconsidered only for a later milestone requiring multiple large scenes, downloadable content, external catalogs, or demonstrated memory pressure.

Data Persistence and Networking

Baseline sessions begin fresh and persist nothing between launches. No save file, PlayerPrefs gameplay state, cloud synchronization, accounts, networking, or backend service is included.

Runtime API routing, authentication/authorization, databases, background jobs, remote file storage, and security-sensitive external services are not applicable to this local single-player Baseline. This is an explicit scope decision, not an unresolved architectural placeholder.

Settings persistence is deferred with the broader options suite. The architecture must not introduce abstractions for hypothetical multiplayer or saves.

Audio

Use Unity’s built-in audio only if functional cues are added after the visual loop is stable. Gameplay comprehension never depends on audio. FMOD, Wwise, voice, and adaptive music systems are outside the Baseline.

Testing Strategy

Edit Mode tests cover:

  • Resource accounting and Recipe validation
  • Job timing, completion, and cancellation
  • Inventory reservation and exact T1 restoration
  • Modifier stacking, rounding, removal, and HP clamping
  • Quest counters and duplicate-event handling
  • State-machine transitions and recovery rules

Play Mode tests cover:

  • Composition-root and scene-reference wiring
  • Input adapters and placement feedback
  • Representative NavMesh routes
  • World/UI synchronization
  • Morale radius integration
  • Defeat, encounter reset, and recovery
  • One complete production-to-Quest journey

Tests use builders, fake clocks, and deterministic IDs. Every corrected transaction or transition defect receives a regression test.

Performance validation runs in a Windows development build using the documented ten-minute workload. Manual evaluation covers comprehension, causality, aggression-versus-preparation perception, resize behavior, and creator motivation.

Architecture Decision Records

ADR-001 — Keep authoritative gameplay outside MonoBehaviours
Unity objects adapt engine facilities; plain C# owns rules and session state.

ADR-002 — Treat every cross-system mutation as a transaction
Commands validate all conditions before committing, and events publish only after success.

ADR-003 — Prefer explicit Baseline mechanisms over speculative frameworks
No ECS, general RPG framework, behavior-tree package, Addressables, persistence, network layer, or third-party RTS starter is introduced without demonstrated need.

ADR-004 — Make observability part of correctness
Every authoritative state needed to understand production, combat, and Quests is available in snapshots suitable for UI, diagnostics, and tests.

ADR-005 — Preserve the Baseline boundary
Extensions may add capabilities through the domain and adapter seams, but must not silently expand the contracted experiment.

Cross-cutting Concerns

These patterns apply to every system and are mandatory for all implementations.

Error Handling

Strategy: Typed results for expected gameplay failures, startup validation for authored-data failures, and exceptions for broken invariants.

Error classes

Class Handling
Expected refusal Return CommandResult; show blocker and remedy; do not mutate or log as an error.
Invalid authored data Reject session startup with asset/reference context.
Recoverable integration problem Log a warning and enter an explicitly defined fallback state.
Broken invariant Throw, log as an error at the Unity boundary, and stop the affected session safely.

Development and test builds fail loudly. Player builds show a concise critical error panel when safe continuation is impossible.

Empty catch blocks are forbidden. Do not catch Exception merely to continue with potentially corrupt state.

CommandResult result = session.StartCraft(command);

if (!result.Succeeded)
{
    craftView.ShowBlocker(
        result.Code,
        result.Blocker,
        result.Remedy);

    return;
}

Logging

Format: Structured plain text
Destination: Unity Console through IGameLogger
External service: None

Domain code never calls UnityEngine.Debug directly.

Level Usage
Error Unexpected failure or broken invariant
Warning Handled unexpected condition or degraded fallback
Info Major lifecycle and gameplay milestones
Debug Command validation and state transitions
Trace Detailed timing diagnostics; disabled by default

Every record includes level, category, stable event name, session ID, and relevant entity, command, event, or job IDs.

Do not log every frame, timer tick, HP refresh, or UI refresh. Development builds enable Debug; release builds default to Info and above. Logs must not include usernames, secrets, or environment tokens.

_logger.Info(
    category: "Production",
    eventName: "CraftCompleted",
    context: new LogContext(sessionId, jobId, recipeId));
INFO Production CraftCompleted session=baseline-01
job=job-0042 recipe=t2-metal-armor

Configuration

Approach: Typed configuration separated by responsibility.

  • Genuine invariants use named C# constants.
  • Tunable values use immutable, validated ScriptableObject assets.
  • Runtime systems receive typed configuration through constructors.
  • Runtime state never mutates configuration assets.
  • Unity build profiles and Project Settings own platform/build configuration.
  • Player-settings persistence and remote configuration are deferred.

Suggested domain configurations:

EconomyConfig
CombatConfig
AiConfig
CameraConfig
FeedbackConfig

Recipes, items, units, Skills, and Quests remain individual definition assets. Names or metadata state units explicitly, such as CraftDurationSeconds and AcquireRadiusMeters.

Startup validation rejects invalid ranges, negative durations, duplicate IDs, missing references, and contradictory eligibility.

public sealed class ProductionSystem
{
    public ProductionSystem(
        EconomyConfigData config,
        IGameClock clock,
        IGameLogger logger)
    {
        _config = config;
        _clock = clock;
        _logger = logger;
    }
}

Every core-journey tuning change records its old value, new value, reason, and required retest.

Event System

Pattern: Synchronous, session-scoped, strongly typed dispatcher.

Events are immutable past-tense records:

JobStarted
CraftCompleted
ItemEquipped
UnitDefeated
QuestCompleted

Dispatch occurs only after authoritative state commits. Events cannot veto or rewrite the completed transaction. Subscriber order must not affect gameplay outcomes.

Atomic gameplay consequences, including qualifying session-counter increments, belong inside the originating command handler—not in subscribers. Events serve presentation, notifications, and diagnostics after those counters commit.

Subscriptions are disposable and released with their owning session or view. Events contain stable IDs when idempotency matters. There is no persistent event history or replay system.

public sealed record CraftCompleted(
    EventId EventId,
    JobId JobId,
    RecipeId RecipeId,
    ItemInstanceId ItemId,
    InventorySlotId SlotId);

_events.Publish(new CraftCompleted(
    eventId,
    job.Id,
    job.RecipeId,
    item.Id,
    job.ReservedSlotId));

A subscriber failure is logged with event and subscriber context. Independent presentation and diagnostic subscribers may continue; domain correctness cannot depend on their ordering or success.

Debug and Development Tools

Provide a read-only diagnostic overlay showing:

  • Session ID, clock state, and frame rate
  • Resources and recent committed deltas
  • Active jobs, reservations, IDs, and remaining durations
  • Unit state, target, path status, HP derivation, and modifiers
  • Monster and Deer state-machine information
  • Quest counters, processed-event count, and Quest states
  • Last command result and recent domain events
  • Placement-pad occupancy and validation
  • Optional navigation paths and AI-radius gizmos
  • Performance markers for session, AI, UI, and command work

F3 toggles the overlay in the Editor and Development Builds.

State-changing test controls live in a separate guarded panel. They use ordinary commands where possible and log DebugActionExecuted.

#if UNITY_EDITOR || DEVELOPMENT_BUILD
_debugOverlay.Initialize(sessionDiagnostics);
#else
Destroy(_debugOverlay.gameObject);
#endif

No debug UI is included in non-development player builds. Debug tools cannot be required to complete or understand the Baseline. Evaluation records whether they were disabled. Inspector or MCP access never counts as player-facing validation.

Project Structure

Organization Pattern

Pattern: Hybrid—technical boundaries at the top level, game systems within each boundary.

Rationale: Top-level folders and Assembly Definitions enforce dependency direction. Feature folders keep related production, Inventory, combat, and Quest code discoverable without mixing domain rules with Unity or presentation code.

Directory Structure

TestGame/
├─ Assets/
│  ├─ TestGame/
│  │  ├─ Domain/
│  │  │  ├─ TestGame.Domain.asmdef
│  │  │  ├─ Common/
│  │  │  │  ├─ Commands/
│  │  │  │  ├─ Events/
│  │  │  │  ├─ Identifiers/
│  │  │  │  ├─ Logging/
│  │  │  │  ├─ Results/
│  │  │  │  └─ Time/
│  │  │  ├─ Session/
│  │  │  ├─ Economy/
│  │  │  │  ├─ Resources/
│  │  │  │  ├─ Production/
│  │  │  │  └─ Recipes/
│  │  │  ├─ Inventory/
│  │  │  ├─ Equipment/
│  │  │  ├─ Effects/
│  │  │  ├─ Units/
│  │  │  ├─ Combat/
│  │  │  ├─ Skills/
│  │  │  ├─ Quests/
│  │  │  └─ Placement/
│  │  ├─ Unity/
│  │  │  ├─ TestGame.Unity.asmdef
│  │  │  ├─ Definitions/
│  │  │  ├─ Input/
│  │  │  ├─ Camera/
│  │  │  ├─ Selection/
│  │  │  ├─ Navigation/
│  │  │  ├─ Placement/
│  │  │  ├─ Units/
│  │  │  ├─ Combat/
│  │  │  ├─ Effects/
│  │  │  ├─ World/
│  │  │  ├─ Diagnostics/
│  │  │  └─ Logging/
│  │  ├─ Bootstrap/
│  │  │  ├─ TestGame.Bootstrap.asmdef
│  │  │  └─ Composition/
│  │  ├─ Presentation/
│  │  │  ├─ TestGame.Presentation.asmdef
│  │  │  ├─ Common/
│  │  │  ├─ Hud/
│  │  │  ├─ Selection/
│  │  │  ├─ Buildings/
│  │  │  ├─ Production/
│  │  │  ├─ Inventory/
│  │  │  ├─ Equipment/
│  │  │  ├─ Combat/
│  │  │  ├─ Skills/
│  │  │  ├─ Quests/
│  │  │  ├─ Placement/
│  │  │  ├─ Notifications/
│  │  │  └─ Diagnostics/
│  │  ├─ Content/
│  │  │  ├─ Definitions/
│  │  │  │  ├─ Config/
│  │  │  │  ├─ Resources/
│  │  │  │  ├─ Recipes/
│  │  │  │  ├─ Items/
│  │  │  │  ├─ Buildings/
│  │  │  │  ├─ Units/
│  │  │  │  ├─ Skills/
│  │  │  │  └─ Quests/
│  │  │  ├─ Prefabs/
│  │  │  │  ├─ Buildings/
│  │  │  │  ├─ Units/
│  │  │  │  ├─ Items/
│  │  │  │  ├─ Effects/
│  │  │  │  ├─ World/
│  │  │  │  └─ UI/
│  │  │  ├─ Art/
│  │  │  │  ├─ Models/
│  │  │  │  ├─ Materials/
│  │  │  │  ├─ Textures/
│  │  │  │  ├─ Animations/
│  │  │  │  ├─ VFX/
│  │  │  │  └─ Icons/
│  │  │  ├─ Audio/
│  │  │  │  ├─ SFX/
│  │  │  │  └─ Mixers/
│  │  │  ├─ UI/
│  │  │  │  ├─ Fonts/
│  │  │  │  ├─ Sprites/
│  │  │  │  └─ Themes/
│  │  │  └─ Input/
│  │  │     └─ TestGameInputActions.inputactions
│  │  ├─ Scenes/
│  │  │  └─ BaselineSandbox.unity
│  │  ├─ Settings/
│  │  │  ├─ Rendering/
│  │  │  └─ Physics/
│  │  └─ Tests/
│  │     ├─ EditMode/
│  │     │  ├─ TestGame.Tests.EditMode.asmdef
│  │     │  ├─ Common/
│  │     │  ├─ Economy/
│  │     │  ├─ Inventory/
│  │     │  ├─ Equipment/
│  │     │  ├─ Effects/
│  │     │  ├─ Units/
│  │     │  ├─ Combat/
│  │     │  ├─ Skills/
│  │     │  ├─ Quests/
│  │     │  └─ Placement/
│  │     └─ PlayMode/
│  │        ├─ TestGame.Tests.PlayMode.asmdef
│  │        ├─ Composition/
│  │        ├─ Input/
│  │        ├─ Navigation/
│  │        ├─ Placement/
│  │        ├─ Presentation/
│  │        └─ Journeys/
│  ├─ Settings/
│  └─ ThirdParty/
├─ Packages/
│  ├─ manifest.json
│  └─ packages-lock.json
└─ ProjectSettings/

All first-party files belong under Assets/TestGame. Package Manager dependencies remain under Packages. Imported source assets remain isolated under Assets/ThirdParty/<VendorOrPackage>.

No Resources, StreamingAssets, Addressables groups, save-data folders, network folders, or deferred content categories are created for the Baseline.

System Location Mapping

System Location Responsibility
Session lifecycle Domain/Session Authoritative session root and snapshots
Composition Bootstrap/Composition Validate and connect definitions, session, adapters, and presenters
Commands, results, events Domain/Common Shared typed interaction contracts
Clock and timers Domain/Common/Time Elapsed-time abstraction and timed-state rules
Storage/resources Domain/Economy/Resources Quantities and exact accounting
Recipes/jobs Domain/Economy/Recipes, Production Validation, input commitment, timing, cancellation, completion
Inventory Domain/Inventory Slot ownership, reservations, and item instances
Equipment Domain/Equipment Eligibility and equip/remove transactions
Stat effects Domain/Effects Modifier sources, stacking, rounding, and clamping
Unit state Domain/Units Identities, health, roles, and state machines
Combat Domain/Combat Attacks, damage, defeat, recovery, encounter reset
Skills Domain/Skills Learn, equip, target, execute, and cooldown rules
Quests Domain/Quests Counters, acceptance, progress, and completion
Placement rules Domain/Placement Pad eligibility and occupancy
Input/control groups Unity/Input, Unity/Selection Convert Input System activity into commands
Camera Unity/Camera Pan, rotate, zoom, and framing bounds
Navigation Unity/Navigation Agent paths and arrival/failure reports
Placement world adapter Unity/Placement Preview, pad detection, and visualization
Unit world adapters Unity/Units, Unity/Combat Bind GameObjects and engine queries to domain state
Morale radius Unity/Effects Spatial membership and visible area
HUD/panels Presentation/Hud and feature folders Render snapshots and submit commands
World feedback Presentation/Combat, Notifications, Placement Damage, effects, blockers, and confirmations
Definition types/assets Unity/Definitions, Content/Definitions ScriptableObject schemas, instances, and conversion
Diagnostics Unity/Diagnostics, Unity/Logging, Presentation/Diagnostics Logging, overlays, profiling, and guarded controls
Domain tests Tests/EditMode/<System> Rules, transactions, calculations, and transitions
Integration tests Tests/PlayMode/<Integration> Scenes, adapters, navigation, UI, and journeys

Naming Conventions

Code elements

Element Convention Example
Namespace TestGame.<Boundary>.<Feature> TestGame.Domain.Production
Class, record, enum PascalCase noun ProductionJob
Interface I + PascalCase IGameClock
Method PascalCase verb phrase StartCraft
Property PascalCase noun RemainingSeconds
Private field _camelCase _activeJobs
Parameter/local camelCase recipeId
Constant PascalCase InventoryCapacity
Boolean Positive Is/Has/Can form CanEquip
Command Imperative + noun + Command StartCraftCommand
Event Past-tense fact CraftCompleted
Error code Stable PascalCase identifier InventoryFull
Test Method_WhenCondition_ExpectedResult CancelCraft_WhenActive_RestoresInputs

One public top-level type is allowed per C# file, and the filename matches it.

Game assets

  • Scenes and prefabs: PascalCase.
  • Definitions: <Type>_<Id>, such as Recipe_IronSword.
  • Materials: M_<Name>.
  • Textures: T_<Name>.
  • Sprites: S_<Name>.
  • Animator controllers: AC_<Subject>.
  • Animation clips: <Subject>_<Action>.
  • Audio clips: SFX_<Action>.
  • UI prefabs: UI_<Role>.
  • Stable content IDs: lowercase kebab-case, such as t2-metal-armor.

Use canonical GDD vocabulary. Avoid vague names such as Manager, Helper, Util, and Data when a specific role can be named.

Architectural Boundaries

  • Domain contains no UnityEngine references.
  • Unity adapters may reference Domain but not Presentation implementation.
  • Presentation references Domain snapshots and narrow Unity-facing interfaces.
  • Bootstrap alone references Domain, Unity, and Presentation to construct the application.
  • Presentation submits commands and never mutates runtime state directly.
  • ScriptableObject instances remain separate from mutable session objects.
  • Editor-only code lives in Editor subfolders outside runtime assemblies.
  • Common is used only for proven shared concepts, never miscellaneous helpers.
  • Tests mirror their production ownership.
  • Third-party types do not cross into Domain contracts; adapters isolate them.
  • A feature may span boundaries, but each file has one unambiguous responsibility.

Implementation Patterns

These patterns are mandatory wherever applicable. They remove implementation choices that different agents might otherwise resolve incompatibly.

Novel Patterns

Reserved Outcome Transaction

Purpose: Coordinate committed inputs, Building occupancy, exact Inventory reservation, timed completion, and full cancellation restoration without partial state or inferred refunds.

Components:

  • TransactionPlan — immutable accepted inputs, destination, and restoration plan
  • ProductionJob — plan, lifecycle, and remaining duration
  • CommittedResource — exact resource ID and quantity
  • CommittedItem — exact item instance and original slot
  • InventoryReservation — exact slot and expected output
  • ProductionSystem — sole validator and transaction owner
  • CommandResult — side-effect-free rejection
  • Post-commit events — presentation, progress, and diagnostics facts

Lifecycle:

Requested
  → validate every precondition
  → atomically reserve destination, commit inputs, and create job
  → Running
      ├─ cancel → restore every committed input exactly → Cancelled
      └─ finish → replace exact reservation with output → Completed
  → publish committed event

Once accepted, the job contains everything needed to complete or fully restore itself. Cancellation never recalculates a refund from the current Recipe definition. Partial refunds are unsupported.

T2 Armor records the exact T1 item instance and its original slot, then reserves that slot for the output.

public CommandResult CancelJob(JobId jobId)
{
    ProductionJob job = _jobs.GetActive(jobId);

    foreach (CommittedResource resource in job.Plan.Resources)
        _storage.Add(resource.ResourceId, resource.Quantity);

    foreach (CommittedItem item in job.Plan.Items)
        _inventory.Restore(item.OriginalSlotId, item.Item);

    _inventory.ReleaseOrRestore(job.Plan.Destination);
    _buildings.MarkIdle(job.BuildingId);
    _jobs.MarkCancelled(jobId);

    _events.Publish(new JobCancelled(
        _eventIds.Next(),
        job.Id,
        job.RecipeId));

    return CommandResult.Success();
}

Use this pattern whenever an operation commits inputs before delayed delivery.

Causal Feedback Contract

Purpose: Make player-visible consequences and refusals precisely explainable without coupling domain logic to UI strings.

Components:

  • CommandResult with stable refusal code and blocker/remedy arguments
  • Typed player-visible change records
  • Committed domain events
  • Authoritative snapshots
  • Presenters and notification policy

Flow:

Player action
  → validate
      ├─ reject → stable code + blocker/remedy arguments
      └─ commit → typed change + event
                     ├─ presenter reads fresh snapshot
                     ├─ persistent UI displays current truth
                     └─ transient UI highlights the transition

Typed changes are required for player-visible resource, job, Inventory, equipment, Skill, HP, damage, cooldown, loot, Quest, placement, defeat, recovery, and encounter-reset consequences. Internal bookkeeping changes remain diagnostic.

Payloads contain exact values and cause IDs, never formatted UI strings. Persistent UI remains authoritative after transient feedback disappears.

public sealed record HpChanged(
    UnitId UnitId,
    int PreviousCurrentHp,
    int CurrentHp,
    int PreviousMaxHp,
    int CurrentMaxHp,
    EffectSourceId CauseId);

public void Present(HpChanged change)
{
    UnitSnapshot current = _session.GetUnit(change.UnitId);

    _unitView.SetHealth(current.CurrentHp, current.MaximumHp);
    _notifications.ShowHpChange(
        change.PreviousMaxHp,
        change.CurrentMaxHp,
        change.CauseId);
}

Use this pattern for every player-triggered command and player-visible outcome.

Definition-to-Session Boundary

Purpose: Preserve convenient Unity authoring without leaking ScriptableObject identity, mutability, or Unity serialization into domain logic.

Components:

  • ScriptableObject definition and catalog assets
  • DefinitionValidator
  • Asset-to-domain converters
  • Immutable DefinitionRegistry
  • Separate UnityContentRegistry
  • Composition root

Flow:

Authored assets
  → validate values, IDs, uniqueness, and references
  → convert asset references to stable IDs
  → create immutable domain records
  → validate domain relationships
  → construct session and Unity content registry

Domain definitions contain no UnityEngine.Object, prefab, sprite, asset-path, or ScriptableObject reference. Assets and paths never serve as gameplay identity. Conversion runs once during composition; any failure blocks session startup and identifies the source asset and field.

DefinitionBuildResult result = _definitionBuilder.Build(_catalog);

if (!result.Succeeded)
    throw new DefinitionValidationException(result.Errors);

GameSession session = new(
    definitions: result.DomainRegistry,
    clock: _clock,
    logger: _logger);

_contentRegistry.Initialize(result.UnityContent);

Use this pattern for every authored gameplay definition.

Standard Patterns

Component Communication

Pattern: Explicit dependency injection with boundary-specific references.

  • Plain C# services and presenters use constructor injection.
  • MonoBehaviours use private serialized references for required Unity objects.
  • The composition root supplies runtime dependencies.
  • Same-GameObject GetComponent is allowed only during initialization and cached.
  • Direct interfaces handle commands; typed events communicate committed facts.
  • Find*, mutable singletons, service locators, and repeated runtime discovery are forbidden.
public sealed class ProductionPresenter
{
    public ProductionPresenter(
        IGameSession session,
        IProductionView view,
        IGameLogger logger)
    {
        _session = session;
        _view = view;
        _logger = logger;
    }
}

Entity Creation

Pattern: Domain-first creation with focused Unity prefab factories.

  • Create or accept authoritative domain identity before a world view.
  • Resolve prefabs through UnityContentRegistry.
  • Bind every adapter to a stable domain entity ID.
  • Gameplay code does not call Instantiate directly.
  • Scene-authored entities register through composition.
  • Pools are profiling-driven and own no authoritative state.
ItemInstance item = _session.CreateCraftedItem(itemDefinitionId);

ItemView view = _itemViewFactory.Create(item.Id, itemDefinitionId);
view.Bind(item.Id);

State Transitions

Pattern: Centralized guarded transition methods.

  • Represent state with one enum or sealed state type, not competing booleans.
  • Only the owning machine changes state.
  • Validate transitions through an explicit transition table.
  • Run exit behavior, replace state, run entry behavior, then publish.
  • Animation follows gameplay state and never owns it.
  • Invalid transitions fail loudly in development and tests.
public void TransitionTo(UnitState next, TransitionCause cause)
{
    if (!_transitionTable.IsAllowed(State, next))
        throw new InvalidStateTransitionException(State, next, cause);

    UnitState previous = State;

    Exit(previous);
    State = next;
    Enter(next, cause);

    _events.Publish(new UnitStateChanged(
        _eventIds.Next(),
        Id,
        previous,
        next,
        cause));
}

Data Access

Pattern: Injected typed registries and narrow snapshots.

  • Domain definitions come from typed registries keyed by stable IDs.
  • Runtime state remains owned by GameSession.
  • Consumers receive immutable snapshots, not mutable collections.
  • Unity content uses a separate typed registry.
  • Required missing data fails during composition.
  • Optional content uses explicit TryGet.
  • Commands contain domain IDs, never GameObject references.
  • No Asset Database, Resources.Load, string paths, or generic data manager.
RecipeDefinition recipe = _recipes.Get(command.RecipeId);
ProductionSnapshot state =
    _session.GetProductionSnapshot(command.BuildingId);
Sprite icon = _content.GetItemIcon(recipe.OutputItemId);

Consistency Rules

Concern Convention Enforcement
Identity Stable typed ID value objects Constructors and definition validation
Mutation Commands are the only public mutation entry point Domain API and tests
Failure Typed result for expected refusal Command-handler contract
Transaction Validate all, then commit once Transaction tests
Events Immutable, typed, past-tense, post-commit Dispatcher API
Time Session clock and explicit elapsed seconds No domain Unity-time reference
State One explicit state with guarded transitions Transition tables and tests
Definitions Strict ScriptableObject-to-domain conversion Assembly boundary and validator
Presentation Snapshots plus selective typed changes Presenter interfaces and UI tests
Unity references Serialized or composition-injected Scene validation
Creation Focused factories bind views to domain IDs Factory APIs
Data lookup Typed registries; no strings or global manager Registry interfaces
Logging Structured categories and stable event names IGameLogger
Tests Every corrected rule defect gets a regression test Review checklist
Scope No generalized feature until a Baseline need exists ADR review

Architecture Validation

Validation Summary

Check Result Notes
Decision Compatibility Pass Bootstrap assembly removes the composition dependency conflict; domain counters commit atomically.
GDD Coverage Pass Every identified system, platform constraint, performance requirement, and exclusion has architectural support.
Pattern Completeness Pass Creation, communication, transitions, errors, data access, events, timing, transactions, and presentation causality are defined.
Epic Mapping Pass All seven development epics map to explicit folders, boundaries, and patterns.
Document Completeness Pass Every mandatory section exists and no placeholder text remains.

Coverage Report

Systems Covered: 15/15
Architectural Decisions: 14
Novel Patterns: 3
Standard Implementation Patterns: 4
Development Epics Mapped: 7/7

Epic Mapping

Epic Primary Architecture Status
1. Play Space and Interaction Unity Input, Selection, Camera, Placement, and Presentation Pass
2. Storage and Production Domain Economy and Reserved Outcome Transaction Pass
3. Crafting, Inventory, and Equipment Domain Production, Inventory, Equipment, and Effects Pass
4. Units, Combat, and Morale Domain Units/Combat/Effects and Unity navigation adapters Pass
5. Loot, Skills, and Quests Domain Skills/Quests, entity factories, and atomic counters Pass
6. UX, Accessibility, and Feedback Presentation boundary and Causal Feedback Contract Pass
7. Evaluation and Stabilization Edit Mode, Play Mode, diagnostics, and build profiling Pass

Issues Resolved

  1. Added TestGame.Bootstrap as the only assembly that composes Domain, Unity, and Presentation.
  2. Moved qualifying progress-counter updates into their originating authoritative transactions.
  3. Added the executive summary, existing-project initialization status, starter-provided labels, and explicit non-applicable infrastructure decisions.

Validation Date

2026-08-02

Overall Status: PASS

Development Environment

Prerequisites

  • Unity Hub
  • Unity Editor 6000.5.6f1 with Windows Build Support
  • A C# IDE supported by the project, such as Visual Studio or Rider
  • Git
  • Node.js 18 or newer for optional MCP tooling
  • Python/uv as required by MCP for Unity’s local server
  • The existing Unity project at TestGame/

The repository already contains an initialized Universal 3D project. Do not create a replacement project or run a starter initialization command.

AI Tooling

Tool Purpose Install type
CoplayDev MCP for Unity Unity Editor inspection, scene/asset operations, Console access, and Test Runner automation Unity Package Manager plus local MCP server
Context7 Current, version-specific Unity and package documentation Remote MCP or local npx client

MCP for Unity setup

  1. Open TestGame/ in Unity 6000.5.6f1.
  2. Open Window → Package Manager.
  3. Select Add package from git URL.
  4. Add https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity#main.
  5. Open Window → MCP for Unity.
  6. Choose Configure All Detected Clients and verify the local connection.
  7. Keep MCP editor access local and require deliberate authorization for editor-changing operations.

MCP tooling is development-only and must not become a runtime or player-build dependency.

Context7 setup

Configure the MCP client to use either Context7’s remote endpoint or its local package:

https://mcp.context7.com/mcp
npx -y @upstash/context7-mcp

Use an API key only when required for the selected access tier, and store it in the MCP client’s secret/environment configuration rather than the repository.

Project Setup and Verification

  1. Open the existing TestGame/ folder through Unity Hub.
  2. Confirm the Editor reports version 6000.5.6f1.
  3. Allow Unity Package Manager to restore the pinned dependencies.
  4. Confirm URP, Input System, AI Navigation, uGUI, and Test Framework packages resolve without errors.
  5. Configure MCP for Unity and Context7 if AI-assisted Editor access is desired.
  6. Run Edit Mode and Play Mode tests through Unity Test Runner.
  7. Open BaselineSandbox.unity once created and validate the composition root before implementing feature systems.

No project initialization command is required.

First Implementation Steps

  1. Create the four Assembly Definitions and dependency direction.
  2. Establish typed IDs, CommandResult, the clock, logger, and event dispatcher.
  3. Implement definition validation and strict ScriptableObject conversion.
  4. Build the smallest production transaction with Edit Mode tests.
  5. Add Unity adapters and presentation only after the domain behavior passes.