Project Damocles · Developer blueprint · Illustrative only

Legacy behaviour to a modern codebase.

A detailed engineering example showing how a rights-cleared legacy-software specification could become a maintainable modern implementation with explicit state, contracts, tests and platform boundaries.

This page uses invented names, generic pseudocode and conventional software-engineering patterns. It does not disclose Damocles recovery methods, evidence, data structures, addresses, identifiers or private implementation details.

First principle

Define “full understanding” honestly.

If the original source code is missing, a team cannot truthfully claim complete knowledge of every original instruction, internal structure or developer intention. That historical understanding remains bounded by the lawfully available evidence.

What the team can achieve is full engineering ownership of the new codebase: every module has a stated purpose; every state transition has an owner; every external dependency sits behind an interface; every supported behaviour has an acceptance test; and every deliberate difference is recorded.

The conversion target is therefore not “unknown old code rewritten line for line.” It is a modern system whose required behaviour is explicit enough to implement, inspect, test, maintain and port again.

01 · End-to-end programme

Do not begin with rendering.

Begin by deciding exactly what may be built, what behaviour is in scope and how a reviewer will recognise success. Architecture follows the contract—not the other way around.

  1. Gate 0

    Authority and product boundary

    Record who may approve the work, which materials may be used, which platforms are contemplated and which content remains unavailable.

    Deliverable: signed scope and rights assumptions
  2. Stage 1

    Behavioural specification

    Describe supported user actions, visible outcomes, state changes, timing expectations, failure cases and deliberate unknowns using platform-neutral language.

    Deliverable: versioned behaviour catalogue
  3. Stage 2

    Domain model and contracts

    Define authoritative state, commands, events, subsystem ownership and legal state transitions. Resolve contradictory requirements before implementation.

    Deliverable: schemas, invariants and interface contracts
  4. Stage 3

    Executable vertical slice

    Implement one complete user journey through input, simulation, state, presentation, persistence and restart. Avoid isolated demonstrations that cannot join together.

    Deliverable: smallest reviewable product path
  5. Stage 4

    Verification and controlled expansion

    Lock accepted scenarios, add one subsystem or content group at a time, and require existing outcomes to remain stable unless a reviewed change says otherwise.

    Deliverable: regression suite and decision log
  6. Stage 5

    Platform productisation

    Connect approved platform services, accessibility, packaging, diagnostics and distribution while keeping platform code outside the authoritative domain.

    Deliverable: release candidate per target platform

02 · Understanding model

Build five maps before building the full product.

Each map answers a different engineering question. Together they prevent a visually convincing prototype from hiding missing rules or unclear ownership.

Map A

Functional surface

What can a user do? What can the world do in response? Which journeys are supported, rejected or still unknown?

  • Actions and preconditions
  • Outcomes and failure messages
  • Entry, exit and restart paths
Map B

State ownership

Which subsystem owns each fact, who may change it, and when does a candidate value become authoritative?

  • Session and world state
  • Actor and inventory state
  • Progress and configuration
Map C

Temporal model

Which changes occur on a simulation step, an animation frame, an asynchronous service response or a deliberate save boundary?

  • Authoritative update order
  • Presentation interpolation
  • Pause and resume semantics
Map D

Data and content

Which values are executable rules, validated data, authored presentation or platform configuration?

  • Schemas and versions
  • Stable references
  • Validation and migration
Map E

Platform edges

Which services vary by operating system or device and must therefore sit behind replaceable adapters?

  • Input and windowing
  • Audio, storage and clocks
  • Diagnostics and distribution

03 · Reference architecture

Make dependencies point toward the rules.

The domain should not know whether it is running in a browser, desktop window, console shell or automated test. Platform adapters depend on the domain contract; the domain never imports platform APIs.

Platform edgeWindow · Devices · Audio · Storage · DistributionReplaceable adapters; no gameplay authority
Application orchestrationSession · Scene flow · Save policy · Error handlingCoordinates use cases without owning domain rules
Authoritative domainState · Rules · Transitions · Commands · EventsPlatform-neutral, deterministic where required, directly testable
Versioned content and configurationSchemas · Definitions · Localisation keys · Tuning profilesValidated before a session starts; migrated deliberately
Cross-cutting verification planeUnit contracts · Scenario tests · Adapter tests · Accessibility · Performance · Rights gates

Allowed

Desktop adapter → application → domain

Renderer → read-only presentation snapshot

Persistence adapter → versioned save contract

Rejected

Domain → window or controller API

Renderer → authoritative state mutation

Content file → executable arbitrary logic

04 · Runtime operation

A concrete frame-to-state flow.

The host may render at a variable rate, but supported gameplay outcomes should not depend accidentally on display performance. This generic example separates host time, authoritative updates and presentation.

  1. HostmeasureElapsed()

    Measure elapsed host time, apply a reviewed catch-up limit and update the accumulator.

  2. Input adapterpollDevices()

    Sample available devices and retain edge transitions such as press, release and held state.

  3. Input maptoCommands(samples)

    Convert device samples into stable commands such as move, interact, select and pause.

  4. Applicationroute(commands)

    Handle session-level commands; pass gameplay commands to the authoritative simulation.

  5. Domainstep(previous, commands)

    Evaluate systems in a documented order and return a complete candidate state plus events.

  6. Invariant gatevalidate(candidate)

    Reject impossible references, invalid transitions or corrupted values before committing.

  7. State storecommit(candidate)

    Publish the next immutable authoritative snapshot and append domain events.

  8. Presentersrender(snapshot, alpha)

    Interpolate display-only values, draw the frame, update UI and translate events to audio.

  9. Persistencesave(snapshot)

    Write a versioned save only when policy permits; never serialize transient platform handles.

Generic host-loop pseudocode

let previous = state;
let accumulator = 0;

function hostFrame(hostNow: number) {
  accumulator += clampElapsed(hostNow - lastHostTime);
  const samples = platformInput.pollDevices();
  commandQueue.push(...inputMap.toCommands(samples));

  while (accumulator >= simulationStep) {
    previous = state;
    const commands = commandQueue.consumeForNextStep();
    const result = domain.step(state, commands);
    invariants.assertValid(result.state);
    state = freeze(result.state);
    eventQueue.publish(result.events);
    accumulator -= simulationStep;
  }

  const alpha = accumulator / simulationStep;
  presentation.render(previous, state, alpha);
  presentation.consume(eventQueue.drain());
  platform.scheduleNextFrame(hostFrame);
}

Illustrative pseudocode only. The update interval, system order, state shape and event semantics must come from the approved product specification.

05 · Code contracts

Make invalid ownership difficult to express.

Use small platform-neutral types. Commands request a change; systems decide whether it is legal; events report what happened; only the returned state becomes authoritative.

Commands and events

type Command =
  | { kind: "move"; axis: Vec2 }
  | { kind: "interact" }
  | { kind: "select"; choice: ChoiceRef }
  | { kind: "pause"; paused: boolean };

type DomainEvent =
  | { kind: "transitioned"; to: SceneRef }
  | { kind: "itemChanged"; item: ItemRef }
  | { kind: "interactionRejected"; reason: ReasonRef };

interface StepResult {
  readonly state: GameState;
  readonly events: readonly DomainEvent[];
}

Authoritative state

interface GameState {
  readonly schemaVersion: number;
  readonly simulationTick: number;
  readonly session: SessionState;
  readonly scene: SceneState;
  readonly actors: ReadonlyMap<ActorRef, ActorState>;
  readonly inventory: readonly ItemRef[];
  readonly progress: Readonly<ProgressFlags>;
  readonly random: RandomState;
}

interface PresentationSnapshot {
  readonly previous: GameState;
  readonly current: GameState;
  readonly interpolation: number;
}

Example invariants checked before commit

  • Every actor reference resolves to exactly one actor definition.
  • The active scene exists and contains the player’s authoritative transform.
  • Inventory entries conform to the content schema and duplication policy.
  • A transition target exists and its entry contract accepts the carried state.
  • Simulation counters advance monotonically and remain within supported ranges.
  • Presentation-only values never appear in an authoritative save.

06 · Subsystem ownership

Specify every boundary in both directions.

A subsystem contract should identify its inputs, outputs, authority, failure behaviour and test seam. “Handles gameplay” is not a sufficient responsibility.

SubsystemReceivesOwnsReturnsFailure policyPrimary verification
Input adapterDevice samplesBindings and edge stateNormalised commandsUnknown device input is ignored and reportedAdapter contract tests
ApplicationCommands and lifecycle eventsSession orchestrationDomain requests and save requestsInvalid lifecycle request fails closedUse-case integration tests
NavigationState, movement intent, scene geometryMovement proposal resolutionAccepted transform or rejectionUnsupported destination does not commitBoundary and scenario tests
InteractionState, actor, target and commandInteraction preconditionsState changes and domain eventsRejected reason is explicitRule-table unit tests
TransitionCurrent scene, exit and carried stateScene hand-off transactionDestination scene stateOriginal state remains authoritative on failureEnd-to-end transition scenarios
PersistenceVersioned authoritative snapshotEncoding, migration and atomic storageLoaded state or typed errorCorrupt or future schema never partially loadsRound-trip and migration tests
PresentationRead-only snapshots and eventsFrames, audio and UI stateUser feedbackMissing cosmetic resource uses an approved fallbackVisual, audio and accessibility review
Platform adapterApplication service requestsOS or device API integrationTyped service resultsCapability absence is explicitPer-platform integration suite

07 · Worked sequence

A scene transition as a transaction.

This generic flow shows why implementation detail needs more than a box labelled “change room.” The carried state must remain coherent across validation, loading and commit.

  1. 1
    TransitionSystem.propose(exitRef)

    Resolve the exit definition and verify the current actor satisfies its preconditions.

  2. 2
    ContentStore.requireScene(targetRef)

    Load or obtain the validated destination definition without mutating the active session.

  3. 3
    EntryPolicy.place(carriedState)

    Calculate a legal destination transform and identify retained session, inventory and progress state.

  4. 4
    Invariants.validate(candidate)

    Check references, placement, ownership and version compatibility on the complete candidate.

  5. 5
    StateStore.commit(candidate)

    Replace the old authoritative state once; emit a transitioned event only after success.

  6. 6
    Presenters.consume(event)

    Update camera, UI, audio and loading presentation from the committed event.

08 · Verification strategy

Trace every supported claim to an executable check.

The purpose of testing is not only defect detection. It is to make the new team’s understanding visible and maintainable.

Fast

Contract tests

Commands, invariants, rule tables, schema validation, migrations and adapter behaviour.

Focused

Subsystem scenarios

Movement boundaries, interactions, transitions, inventory changes and save round-trips from declared starting states.

End to end

Journey scenarios

Complete product paths that cross systems and verify retained outcomes rather than internal call counts.

Platform

Integration suites

Packaging, device mapping, storage locations, window lifecycle, audio, performance and clean-machine operation.

Human

Review gates

Usability, accessibility, deliberate differences, historical authority, content rights and release suitability.

Requirement IDGEN-TRANSITION-01
Given

A valid starting scene, one retained item and an available destination.

When

The actor meets the exit precondition and issues the transition action.

Then

The destination becomes active, the retained item remains present, and exactly one transition event is emitted.

Failure

An unavailable destination leaves the starting state authoritative and returns a typed rejection.

Evidence

Scenario result, final-state comparison, event list and reviewed deliberate-difference record.

09 · Implementation possibilities

One owned domain. Several credible hosts.

The architecture does not force a technology choice on day one. A stable domain contract can be hosted by a lean native shell, a full game engine, a browser-capable runtime or several adapters at once. The choice follows product needs, team skills, performance evidence and platform obligations.

Path A · Lean native

Small host, direct control

A C, C++ or Rust domain can sit behind a deliberately thin host. SDL3’s official documentation describes low-level cross-platform access to input, audio and graphics facilities across major desktop and mobile systems.

Strong fit when

  • Fast startup and modest distribution size matter.
  • The presentation requirements are focused.
  • The team wants precise control over the frame, memory and I/O model.

Engineering caution

A light framework means the team must deliberately supply its own editor tooling, asset pipeline, profiling conventions and platform release integrations.

Path B · Engine hosted

Rich tools around an isolated core

The domain can be compiled as an independent runtime module while an engine owns rendering, content authoring, UI and platform services. Epic’s Unreal Engine module documentation provides one concrete example of runtime/editor module separation, dependency declarations and platform-specific inclusion.

Strong fit when

  • Modern 3D presentation and artist workflows dominate production.
  • Editor extensions, cinematics or established platform integrations carry value.
  • The team can enforce a hard boundary between engine objects and authoritative state.

Engineering caution

Do not let convenient engine callbacks become the rules. The engine should translate commands in and snapshots/events out; domain tests should still run without launching the editor.

Path C · Web capable

A portable core with a browser adapter

A suitable portable core may target WebAssembly. Its core specification defines a safe, portable low-level format that is independent of hardware, source language and host environment. A browser presenter could use conventional web rendering or evaluate WebGPU for modern GPU work; WebGPU remains a W3C Candidate Recommendation Draft, so support and fallback policy must be measured rather than assumed.

Strong fit when

  • A frictionless review build or educational demonstrator is valuable.
  • The same behaviour package should run in automated browser scenarios.
  • Distribution without an installer is an explicit product goal.

Engineering caution

Browser lifecycle, storage, security policy, threading and input availability differ from desktop assumptions. Those differences belong in the adapter and capability matrix.

Path D · Hybrid

Multiple products, one behavioural authority

The most strategically interesting option is a shared domain package behind several hosts: a fast command-line scenario runner for CI, a desktop evaluator for specialists, an engine-based presentation build and a browser review experience.

What becomes possible

  • Thousands of headless scenarios can run without rendering.
  • Editors can preview validated content against the same rules as the product.
  • Platform teams can replace presentation without forking behaviour.
  • A save migration can be verified independently of any user interface.

Engineering caution

Shared does not mean universal. Keep the shared surface intentionally small, version it, and allow platform-specific experience where the product benefits.

10 · Production engineering

Design for diagnosis, budgets and change.

A conversion becomes maintainable when developers can explain not only what happened, but why, how long it took, which version produced it and whether the result can be reproduced.

Observability

Build a state timeline, not a print-statement graveyard.

Every accepted command, rejected command, state commit, transition and save can produce a structured diagnostic record with a tick, subsystem, correlation ID and schema version. A developer view can then answer: “Which command changed this field?” without exposing that tooling in a release build.

Determinism

Record the ingredients of a result.

Where repeatability is required, record initial state, ordered commands, fixed-step count, content version and controlled random state. A replay tool should compare authoritative outcomes, not pixels or incidental timestamps.

Performance

Allocate budgets before optimisation.

Set explicit budgets for simulation, presentation submission, streaming, allocations, save latency and startup. Test representative worst cases and report percentiles; an average frame can conceal the hitch that users actually feel.

Content safety

Fail during authoring, not during play.

Schema checks should reject missing references, duplicate stable IDs, unreachable transitions and incompatible versions in the build pipeline. Runtime defensive checks remain, but they are the last guard rather than the normal workflow.

Migration

Treat saved state as a public contract.

Decode old schemas into typed intermediate forms, migrate one version at a time, validate the result, and write atomically. Preserve fixtures for every supported version and define what a future or corrupt save does.

Tooling

Give specialists purpose-built views.

A state inspector, scenario editor, transition graph, content validator and difference viewer can all consume the same contracts. The goal is not a giant universal editor; it is small tools that make uncertainty and ownership obvious.

Illustrative target60 Hz presentation16.67 ms frame interval
Simulation≤ 2.0 msmeasured at a declared stress case
Main-thread submit≤ 4.0 mspresentation work, excluding GPU completion
Transient allocationNear zeroinside the authoritative update path
Save transaction≤ 100 msor asynchronous with honest UI state

These figures are illustrative engineering targets, not measurements from Damocles. A real project must establish budgets from target hardware, content scale and product requirements.

09 · Delivery roadmap

Expand by verified capability, not by file count.

Each phase should leave the product runnable, the contracts current and the evidence stronger than before.

  1. Phase 0

    Authority, scope and risks

    Approve inputs, product target, terminology, security boundary and publication rules.

    Exit: team can state what it may build and what it may not claim.
  2. Phase 1

    Executable skeleton

    Create the domain package, platform interfaces, application shell, schemas, test harness and continuous build.

    Exit: empty session starts, steps, renders and shuts down on every target.
  3. Phase 2

    First complete journey

    Implement one movement, interaction, transition, state-retention and restart path end to end.

    Exit: the journey is repeatable and reviewable without developer intervention.
  4. Phase 3

    System breadth

    Add capabilities in dependency order, expanding schemas and scenario coverage with every reviewed behaviour.

    Exit: supported product journeys are represented by maintained acceptance records.
  5. Phase 4

    Content and presentation

    Connect rights-cleared content, authored modern presentation, accessibility and localisation through validated data.

    Exit: presentation can change without changing authoritative outcomes.
  6. Phase 5

    Platform release candidates

    Complete packaging, storage, devices, performance budgets, diagnostics, clean-machine tests and distribution gates.

    Exit: each platform candidate satisfies the same domain contracts and its own platform checklist.

Definition of done

The new team can explain every supported outcome.

  • Every public or product requirement has an owner, status and acceptance record.
  • Every authoritative field has one subsystem responsible for changing it.
  • Domain packages build and test without window, audio, storage or device APIs.
  • Save data is versioned, validated and covered by forward migration policy.
  • Every platform adapter reports unsupported capabilities explicitly.
  • Presentation cannot mutate authoritative simulation state.
  • Complete user journeys pass from declared starts on supported platforms.
  • Deliberate differences and unresolved behaviours remain visible.
  • Rights, content, accessibility, security and release gates are recorded separately from technical tests.
  • A new developer can trace a user-visible result from requirement to command, system, state, event, presenter and test.