The engine is Dusk. Darkwind is the reference game built with it. This record lists the places where the old name intentionally survives, and the ownership targets for the rename. The plan is DUSK_IDENTITY_AND_REFERENCE_GAME_PLAN.
The rule is correct ownership, not zero search matches. Each old-name occurrence falls into one class:
- Engine branding: changes to Dusk.
- Darkwind game identity or content: stays Darkwind.
- Compatibility or persistent identity: kept, because changing it would break saves, sessions, wire negotiation or retained builds.
- Historical evidence, fixture or credit: kept with its factual meaning.
- Incidental internal label: renamed only when a touched file makes it relevant.
#Retained compatibility identifiers (class 3)
| Location | Identifier | Why it remains | Check |
|---|---|---|---|
packages/sdk/index.ts |
SDK_API = 'darkwind-game-sdk.1' |
Serialized into portable game releases. Older releases name it. | tests/game-sdk.test.ts |
packages/behavior/index.ts |
darkwind-plugin.1 |
Engine plugin contract version | tests/extensions.test.ts |
packages/schema/extensions.ts |
darkwind-extension.1 |
Installed creator extension contract | tests/extensions.test.ts |
packages/agent-tools/index.ts |
darkwind-agent-tools.1 |
Agent tool contract version | tests/agent-tools.test.ts |
packages/net/wire.ts |
darkwind.binary.1.<hash> |
Negotiated WebSocket subprotocol; retained engines expect it | npm run check (generated wire) |
packages/simulation/checkpoint.ts |
darkwind.simulation.1–.7, darkwind.simulation.behavior.1 |
Checkpoint profiles and legacy readers | tests/checkpoints.test.ts |
packages/physics/* |
darkwind-owned-rigid.8, darkwind-owned-scene.1, darkwind-owned-floating.1, darkwind-owned-character.1 |
Owned-physics checkpoint identities | tests/owned-*.test.ts |
apps/player/* browser storage |
darkwind:controls:v1, darkwind:audio:v1, darkwind:visual-quality:v1 |
Player preferences. Renaming would discard settings. | — |
apps/player/* browser storage |
darkwind:development…, darkwind:playtest:…, darkwind:game:…, darkwind:persistent:…, darkwind:crossing:…, darkwind:directory:…, darkwind:room-token, darkwind:lantern-house |
Saves and return credentials | tests/browser/* |
apps/editor/main.ts |
darkwind:editor-key, darkwind:editor-name, darkwind:editor-history-actor |
Editor access and history identity. Renaming would log builders out. | tests/browser/editor-panels.spec.ts |
services/routing/welcome.ts |
darkwind:directory:, darkwind-region: |
Regional directory and storage keys | — |
services/persistent/watchdog.ts |
darkwind:watchdog:ping/pong |
Inter-process protocol with retained hosts | tests/host-watchdog.test.ts |
apps/probe, apps/editor recording messages |
darkwind-take-*, darkwind-series-* |
Cross-window message types with retained players | tests/hosted-recordings.test.ts |
services/storage/objects.ts |
darkwind-backups default bucket |
Existing backup bucket identity | tests/backup.test.ts |
| PostgreSQL | dw_* tables and schemas |
Existing databases and migrations | tests/content-persistent.test.ts |
| Docker / Compose | volumes darkwind-room, darkwind-arrival-v10; service keys darkwind, darkwind-beta |
Existing physical storage and proxy routes | docker compose config |
| Local data | .data/hearth, .data/arrival-art.10, .data/meridian.1 |
Existing room separation | — |
Golden fixtures, docs/evidence, archived recordings |
Recorded strings | Frozen historical evidence | — |
#Operator settings
Every public setting has a canonical DUSK_ name and its legacy DW_ alias. The
policy is implemented once, in deploy/dusk-env.mjs, and used by every service
and launcher entry point (deploy/dusk-env-bootstrap.mjs), the container
entrypoint, the health check, the Vite config and npm run compose:
- Only one name present: use it. Presence counts, not truthiness, so empty and
0are real values. - Both present with the same value: accepted.
- Both present with different values: the process stops with an error naming both settings. Values are never printed.
- Neither present:
DUSK_DEFAULT_<NAME>applies. Images and the local Compose file use this for their defaults, so supplying either name overrides an image default without a false conflict. - After resolution, each process keeps only the
DW_name. Existing code, children and retained older engines read that name, and a launcher's ownDW_override never looks like a conflict.
Settings (each DUSK_X ↔ DW_X): ALLOWED_ORIGINS, ROOM_PASSWORD,
ROOM_PASSWORD_REQUIRED, RELAY_PORT, HTTP_PORT, DATA_DIR, STATIC_DIR,
ENGINE_BUNDLE, GAME_FILE, GAME_SOURCE, PLAYTEST, PHYSICS_BACKEND,
EDITOR_TOKEN, PLAYER_ACCOUNTS, AUTHORING_WORKSPACE, DATABASE_URL,
PERSISTENT_ROOM, HOST_PORT, WORLD_DOCUMENT, ROOM_TEMPLATE,
ROOM_AUTHORITY, ROOM_PROGRAM, SPAWNED_PLACES, ROOM_ROUTES,
ROOM_RSS_LIMIT_MIB, REGION, ROUTER_PORT, OPERATIONS_TOKEN,
PLAYER_TRANSFERS, REMOTE_ROOM_HOSTS, ROOM_HOST_PORT, ROOM_HOST_CAP,
ROOM_HOST_TOKEN, ROOM_SOCKET, ROOM_CAP, CONTROL_PORT, CONTROL_BIND,
CONTROL_TOKEN, POSTGRES_PASSWORD, PHYSICS_TOKEN, PHYSICS_ENDPOINTS,
PHYSICS_OWNERS, PHYSICS_CAPACITY, PHYSICS_ALLOW_INSECURE,
BUILD_DATABASE_URL, BUILD_POSTGRES_PASSWORD, the BACKUP_* settings,
ASSET_PROVIDER_KEY, ASSISTANT_PROVIDER_KEY, CROSSING_VEHICLES,
CROSSINGS_DATA_DIR and the HOST_TOKEN_* family. Browser builds accept only
VITE_DUSK_PLAYTEST ↔ VITE_DW_PLAYTEST. Test and fixture switches (DW_TEST_*,
DW_*_CLIENT_DIR, DW_GPU_PROFILE, DW_BENCH_SECONDS, DW_TERRAIN_*) are not
operator settings and keep only their DW_ names. PORT, PG*, NODE_ENV and
Playwright options are unchanged.
Build arguments (Dockerfile): DUSK_PLAYTEST/DW_PLAYTEST and
DUSK_GAME_SOURCE/DW_GAME_SOURCE. An empty build argument counts as unset;
two different non-empty values fail the build.
Compose. The single-container profiles (compose.coolify.yaml,
compose.beta.yaml, compose.ferry.yaml, compose.meridian.yaml, compose.yaml)
pass both names through unset-preserving. The container resolves them, so DUSK_
names work in Coolify. Values these files fix (port 8787, /data, the static
directory and the beta's required passphrase) stay fixed. A different DUSK_
value for one of them is reported as a conflict. The PostgreSQL multi-service
profiles (compose.persistent.yaml, compose.rooms.yaml, compose.room-hosts.yaml,
compose.cargo.yaml, compose.control.yaml, compose.builds.yaml) interpolate
values into non-Dusk images (database passwords, URLs, host tokens), which YAML
cannot conflict-check. In Coolify they keep their DW_ names. Locally,
npm run compose -- -f <file> … resolves DUSK_ names first. The local host port
follows the same rule: DUSK_HOST_PORT through npm run compose, DW_HOST_PORT
with plain docker compose.
#Deployment and storage map
| Item | Value | Rename policy |
|---|---|---|
| Engine and tool display name | Dusk | Changed |
| Game display name | Darkwind (in-game credit: Dusk Observatory panel) | Kept |
| Source repository | jasona/dusk-engine (renamed from jasona/awaken-engine; GitHub redirects the old URL) |
Renamed outside this pass |
| Coolify game service key | darkwind (compose.coolify.yaml), darkwind-beta (compose.beta.yaml) |
Kept: proxy routes and project identity |
| Named volumes | darkwind-room, darkwind-arrival-v10, garden-ferry-v4-room, meridian-v1-room, darkwind-persistent-*, darkwind-regional-* |
Kept: the same physical data |
| Container data path, user, port | /data, UID/GID 1000:1000, 8787 |
Kept |
| Local data | .data/hearth, .data/arrival-art.10, .data/meridian.1 |
Kept |
| Database names | darkwind database and user, dw_* tables |
Kept |
| Session signing key, passphrases, origins | /data/session-key, operator secrets, public hostname |
Kept; never logged |
| Retained engines | /data/engine-builds/<hash>, /data/engine-pins |
Kept byte-for-byte |
#Darkwind game identity (class 2)
Darkwind's world ID (darkwind), releases such as lantern-house.1.arrival-10,
place, entity and interaction IDs, Elowen's story, the darkwind source import
name in npm run author -- import darkwind, fixture names such as
garden-ferry, and all of games/darkwind/ stay Darkwind.
#Ownership targets
| Milestone | Target files | Change |
|---|---|---|
| R2 tooling UI | editor.html, apps/editor/main.ts |
Dusk World Atelier wordmark and title; draft download name |
| R2 | diagnostics.html, apps/probe/main.ts |
Dusk Observatory wordmark, title and report name |
| R2 | physics.html, apps/physics-lab/main.ts |
Dusk Physics Lab wordmark and title; Darkwind fixture labels identify the game |
| R2 | services/relay/server.ts, services/control/main.ts, services/persistent/main.ts, services/routing/pool.ts |
Startup output names the Dusk service |
| R3 game boundary | apps/player/main.ts |
Remove Darkwind control, gamepad and copy imports; neutral world variable; injected presentation |
| R3 | apps/player/graphics.ts, graphics.worker.ts, graphics-revision.ts, catalog.ts |
Traveler model and rig come from the admitted presentation |
| R3 | apps/player/audio.ts |
Sound graph and frame come from the presentation adapter |
| R3 | services/relay/server.ts |
No default Darkwind world; callers pass one |
| R3 | services/relay/main.ts, services/persistent/world.ts, services/routing/main.ts |
Explicit reference-game composition |
| R4 commands and configuration | tools/cli/*.mjs, deploy/*, Dockerfile*, compose*.yaml, .env.example |
DUSK_* settings with DW_* aliases, npm run dev:darkwind |
#Explicit game-import exceptions
npm run check enforces these boundaries (HOST_GAME_BOUNDARIES in
tools/cli/check-boundaries.ts), including type and dynamic imports:
- Reusable player (
apps/player/): no module importsgames/, except the trusted presentation registryapps/player/installed-games.ts. - Services (
services/): no module importsgames/darkwind/, except the operator composition filesservices/relay/reference-worlds.ts,services/persistent/world.tsandservices/routing/main.ts. The reusablecreateRelayfactory requires an explicit world.
Not covered by that check, by design:
- Diagnostics fixtures that load named demo content:
apps/probe/*,apps/physics-lab/main.ts. - Tools, benchmarks and migrations about Darkwind content:
tools/cli/*,tools/bench/*. - Tests.
#Acceptance record
#R2 — Dusk tooling and engine UI (2/5)
The editor wordmark and title read Dusk World Atelier. Diagnostics read Dusk
Observatory, and the physics page reads Dusk Physics Lab, with a "Dusk · owned
solver" engine label. The player's F2 panel is headed Dusk Observatory, and the
relay and control services print Dusk startup lines. Draft and capability downloads
are named dusk-draft-N.json and dusk-capabilities.json; their contents are
unchanged. Darkwind keeps its title, wordmark and approved traveler. Editor key,
name and history storage keys are unchanged.
Checks (Node 22.23.4, /usr/bin/chromium): tsc --noEmit;
owned-physics.spec.ts:2, editor.spec.ts:7 (draft export name) and
editor-panels.spec.ts:29 (saved editor identity) pass. editor-panels.spec.ts:10
fails identically on the unchanged baseline under software rendering (#enter
stays disabled), so it is pre-existing and is not a rename regression.
Captures (physical GPU, isolated data directory): editor · Observatory · Physics Lab · Darkwind.
#R3 — Explicit game presentation and host boundary (3/5)
The reusable player now hosts a game through GamePresentation
(apps/player/presentation.ts), chosen by the trusted registry
apps/player/installed-games.ts from the admitted world ID. Darkwind's story,
welcome, objectives, journal, satchel text, sound, controls and approved traveler
moved into games/darkwind/presentation.ts. Keeper-story detection was removed.
Other games get the neutral Dusk presentation. The traveler profile reaches the
main-thread renderer, the render worker (per created generation, so device
recovery reuses it) and graphics revisions and portals. Shared default controls
live in packages/input/defaults.ts. They keep the darkwind.player.1 map ID,
because saved rebinding profiles are keyed by it. createRelay requires an
explicit world. The relay picks reference worlds in services/relay/reference-worlds.ts.
Checks (Node 22.23.4): npm run check (types, boundaries including the new host
rule, generated wire); native boundaries, player-graphics-revision, net,
net-interest, relay-shutdown, static-notices, engine-pinning,
playtest-release, game-sdk and development-room tests pass (35). Browser
audio, gamepad and most of player.spec pass under software rendering.
V7: tests/meridian-browser.test.ts (two-player puzzle, travel, reload and
editor publication) passes on the physical GPU.
Pre-existing failures, identical on the R2 baseline af9087f under software
rendering and not caused by the rename: 8 in player.spec.ts (including the
53 / 4 GPU allocation that predates the Vita traveler), 2 in
simulation-recovery.spec.ts, 1 in portal-rendering.spec.ts, the jump hint in
controls.spec.ts, and meridian-browser.test.ts with SwiftShader (#enter
stays disabled). Recorded for follow-up, not fixed in this pass.
Captures (physical GPU): Darkwind welcome · Darkwind journal · Meridian world · Meridian journal.
Known bound: the static index.html is neutral ("Dusk") until the admitted game's
presentation applies, so link previews of a Darkwind deployment say "Dusk".
#R4 — Commands, compatible configuration and deployment readiness (4/5)
npm run dev:darkwind starts Darkwind's polished arrival (same as dev:art,
which remains). dev, dev:editor, dev:meridian and the other commands are
unchanged. Launchers print "Dusk World Atelier (private)". npm run compose
resolves DUSK_ settings before Compose interpolation. Every service and
launcher entry point, the container entrypoint and health check, the Dockerfiles'
build arguments and defaults, and the Vite config follow the policy in
Operator settings.
Checks (Node 22.23.4): npm run build (check, player, workers, editor, server,
author, accounts, retained engine) passes. tests/dusk-env.test.ts (10) covers
canonical-only, legacy-only, equal, unequal (no values in errors), empty and 0,
image-default provenance, HOST_TOKEN_*, the Vite pair, the entrypoint locking
the resolved directory, the independent health probe following a canonical-only
port, and a bootstrapped launcher's child reading the legacy name. deployment,
editor, persistent-world-source and room-routing pass (24 PostgreSQL cases
skipped). Builds with VITE_DUSK_PLAYTEST and VITE_DW_PLAYTEST produce the same
ferry selection, and a conflicting pair fails the build.
Host smoke of the built production server through deploy/entrypoint.sh:
canonical-only and legacy-only settings both start, lock the resolved directory,
ignore the image-default directory and pass deploy/healthcheck.mjs. A conflicting
passphrase pair exits 78 before locking, with no values printed. A copy of the
existing .data/hearth room (revision 1) loads under DUSK_DATA_DIR, admits a
traveler and keeps its signing key. The isolated arrival dev stack starts with
DUSK_-only settings. Effective Compose configuration was inspected for legacy-only
and canonical-only Coolify settings: the volumes are still darkwind-room and
darkwind-arrival-v10 at /data. This is static configuration, not hosted
restart evidence; Docker image builds were not run here.
Found and fixed during this milestone: the resolver's command-line guard matched inside bundled server entry points and exited the server. It now also requires its own filename.