# Production flow: Dream Maker vs Craft++

Research date: 2026-11-02. Reference baseline: BYOND 516.1688, Craft++ 1.0.68.

This document compares the **production and enterprise workflow** of the DM
toolchain (Dream Maker → Dream Daemon → Dream Seeker → Hub) against the
equivalent Craft++ pipeline. It is a flow-and-pipeline comparison, not a
language-feature comparison; the language surface is covered by
`BYOND_DM_PARITY_MATRIX.md`.

Naming rule used throughout: the DM-facing **method and format names are kept
verbatim** (`world.Reboot()`, `world.OpenPort()`, `call_ext()`, `#pragma`,
`.dme`, `.dmb`, `.rsc`) so that DM code and operator knowledge transfer, while
the product brands itself as Craft++. Compatibility names are not BYOND
branding.

## Verification status

| Claim source | Reliability |
|---|---|
| BYOND behaviour cited to byond.com docs / release notes | Verified from primary source |
| BYOND behaviour cited to tgstation-server (TGS) | Verified, but a third-party operator, not BYOND |
| Craft++ behaviour | Read directly from this repository |
| Items marked **[unverified]** | Could not be confirmed from an authoritative page |

Known-primary-source caveat: byond.com's reference and guide are client-rendered
SPAs and the guide PDF is not machine-extractable, so several reference entries
were read through the `ref.dm-lang.org` mirror of the same text. Where the exact
flag or default could not be pinned down it is marked **[unverified]** rather
than guessed.

## 1. The two pipelines side by side

Dream Maker / BYOND:

```
project.dme ──(Build ▸ Compile, dm.exe|DreamMaker)──> project.dmb + project.rsc
     │                                                      │
     │ checked files → #include lines                       │
     └── object tree, maps (.dmm), icons (.dmi), skins (.dmf/.dms)
                                                            │
                              DreamDaemon project.dmb <port> [-trusted|-safe]
                                                            │
                        world.Reboot() / SIGUSR1 ── reload same .dmb
                                                            │
                    Hub entry (world.hub + hub_password) ── "Games Live"
                                                            │
              player: byond://Author.Game[##version=X] ── pager/DS + byond.rsc
```

Craft++:

```
project.cpe ──(environment compile)──> project.cpp + project.rsc
     │                                       │  (.cpp = Craft++ World archive, IR inside)
     │ checked files (IdeFileFlow)           │
     └── map (.cpm/.dmm), icon (.cpi), interface (.cpf/.dmf)
                                             │
              Craft++ --daemon project.cpp --port N [--hub-url/--hub-path]
                                             │
                    world.Reboot() ── shutdown + startup, same process
                                             │
                     HubSite account + publish ── feed/version.json
                                             │
              IDE update check (startup + 15 min) ── ZIP + SHA-256 ── install
```

The shapes are close. The differences that matter in production are:
**code reload, artifact interchange, host security modes, watchdog, and
distribution identity.**

## 2. Stage-by-stage comparison

### 2.1 Project environment and include selection

| | Dream Maker | Craft++ |
|---|---|---|
| Container | `.dme` ("world environment"), main file: `__MAIN__` defined only there; `<stddef.dm>` auto-included first | `.cpe` environment (`IdeFileKind.Environment`) |
| Adding source | New File → checkbox beside the file writes an `#include` into the `.dme` | `IdeFileFlow.Create` + checked-file set; "a checked file is the only one the environment compiles" |
| Order sensitivity | Documented: include order matters only for proc overrides; compiler warns | Not documented as order-sensitive |
| Rename hazard | Renaming `.dme` to another extension drops skins/maps from the build (515.1634) | Extension is what `IdeFileFlow.Classify` keys on — same class of hazard |
| Extra resources | `#include` an additional `.rsc` | Supported by `#include` handling |

**Gap:** Craft++ has no equivalent of `__MAIN__` / `DM_VERSION` / `DM_BUILD`
main-file scoping. A library-style `.cp` file cannot currently ask "am I the
main environment?" — which is how DM libraries avoid double-initialising.

### 2.2 Compile

| | Dream Maker | Craft++ |
|---|---|---|
| Entry point | `Build ▸ Compile`; CLI `dm.exe <project>.dme` (Windows) / `DreamMaker <project>.dme` (Linux) | Environment compile in the IDE; `CraftBuild.Build(inputPath, source, baseDirectory, statements)` |
| Output | `.dmb` (bytecode) + `.rsc` (resource cache) next to the project | `project.cpp` (Craft++ World archive with embedded IR) + `project.rsc` |
| Format promise | Native BYOND bytecode | Deliberately **not** BYOND bytecode; `CraftBuild` states it is "not generated or claimed here" |
| Resource validation | Missing single-quoted resource is a compile error; compiler reuses an existing `.rsc` | `MissingResources` fails the build with the list; `.rsc` is rewritten from collected resources |
| Artifact location | Project directory (runtime CWD is the `.dmb` directory) | Project directory (`artifacts/` reserved for releases, not builds) |
| Debug info | `#define DEBUG` embeds file/line, ~+10% `.dmb` size, required for the profiler; docs say do not ship debug builds | No equivalent DEBUG-in-artifact switch |
| Exit status | Non-zero on compile failure | `CraftBuildResult.Success` |

**Gap (interchange, P2 by design):** a Craft++ `.cpp` cannot be hosted by
Dream Daemon and a `.dmb` cannot be hosted by Craft++. The matrix already
records this as an explicit non-goal unless BYOND interchange becomes one.

**Gap (reproducibility, P1):** `.rsc` reuse is a real production footgun on
BYOND — a stale cache can silently re-embed removed art. Craft++ regenerates
the cache every build, which avoids that specific bug but loses incremental
compile speed. Worth an explicit `--clean-cache` / reuse policy rather than
leaving it implicit.

### 2.3 Error and warning surfacing

| | Dream Maker | Craft++ |
|---|---|---|
| Error list | Output box at the bottom of the IDE; double-click an error jumps to the source line | `ParseError` / `SyntaxValidation`; see `DiagnosticLog` |
| Warning control | `#pragma warn|ignore|error <WarningName>`, `#pragma push`/`pop`; the warning name is printed in compiler output | Directives exist in `Preprocessor.cs` (`compatibility`, `math`, `syntax`, `warn`, `ignore`, `error`, `push`/`pop`, `multiple`). The policy is recorded per name, but no warning emitter consults it yet |
| Version gating | `#pragma compatibility <version>` warns when you use newer features | Not implemented |
| Hard stop | `#error Text`; `#warn` | `#error` / `#warn` handled by the preprocessor |
| Lint names in the wild | `unused_var`, `init_proc`, `frequent_call`, `no parent call` | n/a |

**Gap (P1, corrected):** the directive family is already implemented, so the
remaining work is narrower than a first reading suggested. Two pieces are
missing: (a) stable **warning names** emitted by the analyzer that the recorded
policy can actually gate, and (b) complete `push`/`pop` coverage of the pragma
state. Item (b) was a real defect — `#pragma push` saved version, build, math
and syntax but **not** warning policy, so `#pragma ignore unused_var` inside a
pushed region leaked past `#pragma pop`. That is fixed in `Preprocessor.cs`.

### 2.4 Object tree, maps, icons, interface

| Tool | Dream Maker | Craft++ |
|---|---|---|
| Object tree | Left-hand tab, populated/refreshed by **Compile**; properties pane with alphabetical sort and file pickers for `icon`/`sound`/`file` vars | `TypeRegistry` + `PropertiesPopup`; type-path based |
| Map editor | `.dmm`; Add tool, layer visibility vs selectability, variants tab, pixel offsets, find/replace, undo stack, world preview, Alt+click select-under | `MapEditorWindow` + `CraftMapFile`; `.dmm` recognised and converted |
| Multi-Z | Coordinates x/y/z in editor; `maxx/maxy/maxz` bounds at runtime. No official authoring chapter found **[unverified]** | Z-level planes in map editor and Dream Seeker renderer |
| Icon editor | `.dmi`; pixmaps (static) and movies (animated/directional), states, frame delay row | `IconEditorWindow` + `CraftIconFile`, `.cpi`, frame extraction/playback |
| Interface/skin | `.dmf` skin (windows, controls, macros, panes) with a separate `.dms` for webclient | `DmfInterfaceDocument`, `InterfaceEditor`, `SkinEditorWindow` |

**Gap (P2):** the object tree is not documented as compile-refreshed. BYOND's
tree is a *build product*, which is why "Compile" is the action that makes new
types appear. Craft++ should state its refresh semantics explicitly, because
"my new type isn't in the tree" is a top support question in Dream Maker.

### 2.5 Run and host

| | Dream Daemon | Craft++ |
|---|---|---|
| Launch | `DreamDaemon <world>.dmb <port> [-trusted|-safe] [-invisible] [-logself] [-console] [-version]`; port is positional | `Craft++ --daemon <world.cpp\|world.dm> --port N [--hub-url URL] [--hub-path account.game] [--hub-password S] [--hub-title T]` |
| Port control | `world.port`; `world.OpenPort(port)` with `0`/`"any"`/`"none"`; `ports` option in `cfg/byond.txt` or `-ports` | `WorldHost.StartAsync(port)`; bind address reported after start |
| Interactive console | Requires explicit `-console` since 515.1607; `memory` command prints memory stats to the console (515.1605) | Daemon logs to stdout via `host.Logged` |
| Map send threads | `map-threads` in `cfg/daemon.txt` or CLI (515.1609) | Not exposed |
| Security mode | Trusted vs safe mode chosen at launch; trusted is needed for filesystem/HTTP/native libs. Exact restriction list **[unverified]** | `GameTransportSecurity`; password UI is loopback-only until TLS is implemented (per parity matrix) |
| Shutdown | `world.Del()`; Topic `Del` honoured only from the master server | `ExecuteShutdown` |

**Gap (P1):** there is no `-safe`/`-trusted` equivalent. Operators currently have
one blast radius: whatever the process can reach, the world can reach. A
documented capability set — filesystem roots, network egress, native loads —
is the enterprise requirement, and it is also the prerequisite for shipping
`call_ext`/byondapi safely.

### 2.6 Reboot and live code reload — the biggest structural gap

BYOND: `world.Reboot(reason)` **reloads the world from scratch**; connected
players automatically relogin; on UNIX `SIGUSR1` does the same. It re-reads
**the same `.dmb`**. A running Dream Daemon never picks up a new `.dmb` by
itself — new bytecode only takes effect when a process is launched against the
new file. That is exactly why TGS runs **two** daemons (Alpha/Bravo) in
separate compile directories `A`/`B`, tells the active one to close its port on
reboot, relaunches the inactive one with the new `.dmb`, and **swaps ports**, so
players barely notice. Compile-job directories are reference-counted and deleted
when the last daemon releases its lock.

Craft++ today (`BuiltinProcs.Stubs.cs`, `ExecuteReboot`):

```csharp
// A reboot is a shutdown followed by startup in the same world
// instance. This preserves object/type registrations while allowing
// user lifecycle hooks to release and reacquire resources.
ExecuteShutdown(args);
ExecuteStartup(args);
```

This is a **logical** reboot. It cannot load new code: it never re-reads the
`.cpp` artifact, so `Reboot()` after a deploy is a no-op as far as the running
program is concerned. That is a correctness gap against the documented DM
contract, and it also means Craft++ has no restart-based deployment path at all
today.

**Gap (P0 for a production story).** Two separable pieces:

1. `world.Reboot()` must re-read the world artifact from disk and rebuild
   runtime state, preserving only what the contract says to preserve (players
   relogin; type registrations are rebuilt from the new build, not kept).
2. The dual-process port-swap pattern needs a supported form — either
   `--reboot-exec <path>` (re-exec self against a new artifact) or documented
   `--alpha/--bravo` semantics — because in-place reload cannot be made safe
   for a process that already holds a scheduler, sockets and player sessions.

### 2.7 Deployment and rollout

| | BYOND / TGS | Craft++ |
|---|---|---|
| Mechanism | Replace `.dmb` on disk, restart DD; TGS automates staged compile dirs + port swap | `build_and_upload.sh`: publish → ZIP → hash → stage → publish `version.json` **last** → verify feed and archive digest |
| Atomicity | Per-compile-job directory with lock counting | Staging dir `artifacts/staging/updateddata`, then promote |
| Verification | Operator-run | Script validates `BASE_URL`, feed/archive hashes, required executables, and refuses unless the candidate version is newer than live |
| Rollback | Keep the prior `.dmb` | Not implemented — no previous-version retention or `rollback` path |
| Transport | Out-of-band (git, rsync, TGS) | SSH (`UPDATE_SERVER_SSH`/`UPDATE_SERVER_DIR`) or local dir |
| CI | No official CI; `dm.exe`/`DreamMaker` CLI with non-zero exit is the hook | `.github/workflows/build.yml` restores, builds headless core/Hub/installer, runs three test suites, uploads `.trx`; CI **builds but does not deploy** |

**Gap (P1): rollback.** The feed publishes one version.json. If a bad build
reaches the feed, the only recovery is to rebuild an older version and bump
forward. Retaining the previous N artifacts plus a documented revert path is
cheap insurance for an enterprise operator.

**Finding (P1): feed host mismatch.** `ONLINE_UPDATE_CHECK.md` documents the
default feed as `https://craftplusplus.216.128.145.79.nip.io/updateddata/version.json`, while
`build_and_upload.sh` defaults `BASE_URL` to
`https://craftplusplus.216.128.145.79.nip.io/updateddata` and its validator accepts hostnames
`{craftplusplus.216.128.145.79.nip.io, craftplusplus.216.128.145.79.nip.io}`. `RELEASE_PIPELINE.md` also says the Hub
serves the feed "through the HTTPS host in `BASE_URL`". Two different host forms
and two different ports (`443` vs `8088`) are in play, and the docs say the feed
and archive must share a hostname. This should be resolved to one canonical
origin; a client configured for the documented default and a release published
to the script default will silently disagree.

### 2.8 Distribution and versioning

| | BYOND Hub | Craft++ Hub |
|---|---|---|
| Identity | Hub path `Author.Game`, explicitly immutable — changing it breaks upgrades | `--hub-path account.game`; `HubSite` accounts |
| Listing | Hub entry + "Games Live" box with live player counts | `HubClient` publish with title/status/password |
| Anti-spoof | `world.hub_password` matched against "Require authentication for live games" | `--hub-password` supplied to the daemon |
| Version | **Hub Version** integer (add 1 per upload; drives update notification) + **Display Version** free text | `version` string + `minimumSupportedVersion` in `version.json` |
| Client update pin | `byond://Author.Game##version=X` upgrades only if installed version is lower | IDE compares feed version to installed version, honours `minimumSupportedVersion` and `platforms` |
| Poll cadence | Pager-driven | Startup + every 15 minutes, cache-bypassing so a deploy is visible on the next check |
| Resource caching | Client `byond.rsc`; unchanged art is not re-downloaded; `cache_lifespan`, `preload_rsc` exist (semantics **[unverified]**) | ZIP + SHA-256; full-archive replacement, no delta or shared resource cache |
| Ownership | BYOND account keys; Membership for file space; subscriptions UI | Craft++ Hub accounts, shared with world-server login |
| Build pinning | No runtime "require build ≥ N". Practice is in-DM `byond_version`/`byond_build` checks against a `blacklisted_builds` list (community convention) | `minimumSupportedVersion` in the feed (stronger than BYOND's) |

**Gap (P2): no integer monotonic version.** BYOND's integer Hub Version is crude
but unambiguous for "is there an update?". `minimumSupportedVersion` is better
for hard floors, but there is no cheap monotonic counter to reason about
ordering across channels.

**Gap (P1): no resource delta.** Every Craft++ update ships the whole ZIP.
BYOND's `.rsc` means art changes are the only art that transfers. For an IDE +
runtime that already builds a `.rsc`, hashing resources into a manifest and
serving an incremental overlay is a natural next step, and it directly attacks
the release size growth.

### 2.9 Enterprise integration surface

| Hook | BYOND | Craft++ |
|---|---|---|
| Server-to-server RPC | `world.Export(addr, file, persist, clients, method)` → remote `world.Topic()`; HTTP(S) too, POST/PUT since 516.1664; **blocks the caller** | Not implemented as a network RPC |
| Inbound topic | `world.Topic(T, Addr, Master, Keys)`; default `"ping"` returns players+1; `Reboot`/`Del` honoured only from master | `world.Topic` registered; semantics see parity matrix |
| Native libraries | `call_ext()` / `load_ext()`; since 515.1609 a `"byond:"` prefix selects the **byondapi** ABI (typed values, read/write vars, call procs, `Byond_ThreadSync`); Rust bindings exist | `call_ext` invokes a host-registered delegate only; no native ABI (documented P1) |
| Health probe | `Topic("ping")` convention | No documented liveness endpoint |
| Profiling | Runtime profiler in Dream Seeker, requires `DEBUG` | No profiler |

**Gap (P1): `Topic("ping")`.** A one-line liveness contract is what every
external watchdog keys on. Craft++ should implement the documented
players+1 response so generic monitors work.

**Gap (P2): `world.Export`.** Note TGS abandoned Export for DM→controller RPC
because of an inherited-handle bug and moved to file+JSON+polling. That is
strong evidence not to copy Export naively; if Craft++ adds it, make it
non-blocking and cancellable rather than reproducing the blocking behaviour.

### 2.10 Monitoring, watchdog, restart

BYOND ships **no watchdog**. Production operators use: `Topic("ping")`, a
`sleep`-loop heartbeat written by the DM code, process supervision
(`systemd Restart=on-failure`, `RestartSec`), and TGS's controller, which keeps
the inactive daemon warm, promotes it on a crash, escalates by killing both if
irrecoverable, and raises process priority to Above Normal. A hung (not
crashed) daemon must be detected externally.

Craft++ has `DiagnosticLog` and `host.Logged`, and no supervisor.

**Gap (P1): supervision contract.** Minimum viable enterprise story: a
documented health endpoint, an exit-code contract, and a graceful
`SIGTERM`/`SIGUSR1` mapping (SIGUSR1 = reboot, matching BYOND). Everything else
can be delegated to systemd or an external controller.

### 2.11 Security and artifact trust

BYOND: `.dmb` is **not signed and not encrypted**; the only anti-spoof is
`world.hub_password` for hub presence, which authenticates the *server*, not
players. `#define DEBUG` embeds source file/line and should not ship. Trusted
mode grants broad filesystem access, which is why operators isolate
per-game OS users or containers.

Craft++: `ArtifactPackageInspector` plus SHA-256 on the update archive, staged
publish, and a loopback-only password UI pending TLS. That is already **ahead**
of BYOND on artifact integrity (BYOND has no published digest), and **behind**
on isolation (no capability/mode split) and on TLS for the client login path.

## 3. Prioritized gap list

| P | Gap | DM name to keep | Why it matters |
|---|---|---|---|
| P0 | `world.Reboot()` does not reload the artifact | `world.Reboot()` | Documented contract broken; no restart-based deploy exists. **Implemented** — see §5 |
| P1 | No dual-process / port-swap restart | `world.Reboot`, `world.OpenPort` | Only safe way to change live code |
| P1 | No safe/trusted capability split | `-safe` / `-trusted` | Blast radius; prerequisite for native calls |
| P1 | Warning **emission** for the existing pragma policy | `#pragma warn|ignore|error`, `push`, `pop` | Directives exist; `push`/`pop` state coverage fixed, named emission still missing |
| P1 | No rollback / previous-artifact retention | `version.json` feed | Recovery from a bad release |
| P1 | Feed host/port mismatch between docs and script | n/a | Silent client/feed disagreement |
| P1 | No `Topic("ping")` liveness | `world.Topic` | Generic monitoring |
| P1 | `call_ext`/`load_ext` no native ABI | `call_ext`, `load_ext` | Enterprise extension surface |
| P2 | No `__MAIN__` / `DM_VERSION` / `DM_BUILD` | same | Library main-file scoping |
| P2 | No DEBUG-in-artifact switch | `#define DEBUG` | Diagnostics without shipping source lines |
| P2 | No resource delta / `.rsc` manifest | n/a | Update size |
| P2 | Object-tree refresh semantics undocumented | n/a | Support burden |
| P2 | No monotonic integer version | Hub Version | Update ordering |

## 4. What "replicate the methods, not the brand" means concretely

Keep, verbatim, because operator knowledge and DM source depend on them:

- `world.Reboot()`, `world.OpenPort()`, `world.Del()`, `world.Topic()`,
  `world.Export()`, `world.Import()`, `world.log`, `world.port`
- `call_ext()`, `load_ext()`, `byond:` ABI prefix
- `#pragma warn|ignore|error|push|pop|compatibility`, `#error`, `#warn`
- `__MAIN__`, `DM_VERSION`, `DM_BUILD`, `FILE_DIR`
- `.dme` / `.dmb` / `.rsc` / `.dmm` / `.dmi` / `.dmf` file roles
- Hub Version / Display Version semantics

Rename, because these are product identity rather than API:

- Product and binary names (`Dream Maker`, `Dream Daemon`, `Dream Seeker`,
  `BYOND`) stay Craft++ (`Craft++ IDE`, `Craft++ --daemon`, Craft++ Hub)
- `.cpp` / `.rsc` Craft++ archive formats stay Craft++-owned; do not claim DM
  binary compatibility
- Internal C# types may keep `Byond*` names as implementation detail, but no
  user-visible string should brand the product as BYOND

## 5. Implemented in this change

The first two parity defects of this effort were fixed in code; section 7 is the
running changelog of everything closed since. Both keep the DM names.

**`world.Reboot()` now reloads the artifact.** `Interpreter` exposes
`RebootRequested`, `ExecuteReboot` raises it instead of pretending that
shutdown-plus-startup is a reboot, and `WorldHost.ReloadAsync()` re-reads the
world from disk through the normal `LoadAsync` path and reopens the previously
bound port, so a redeployed artifact takes effect without changing the port
players connect to. The host subscribes only *after* startup execution, so an
unconditional `Reboot()` in `world/New()` cannot loop the loader, and a
concurrent request is coalesced by an interlocked guard. The reload runs off the
executing call stack deliberately: rebuilding the program image from inside the
frames that are still running would corrupt them. When no interpreter is
available (direct builtin use) the old in-place path remains as a fallback.

**`#pragma push`/`pop` now covers warning state.** The saved pragma tuple gained
a warning-policy snapshot; `pop` clears the `DM_WARNING_*` entries set inside
the region and restores the saved ones, so warning policy no longer leaks out of
a pushed block.

## 6. Sources

- DM Guide ch. 1–2 (environment, Build ▸ Compile/Run, output box):
  <https://www.byond.com/docs/guide/chap01.html>,
  <https://www.byond.com/docs/guide/chap02.html>
- DM Reference (preprocessor, `#include`, `#pragma`, `.rsc` cache, `DEBUG`,
  `FILE_DIR`, `__MAIN__`): <https://www.byond.com/docs/ref/info.html>
- Skin parameters: <https://www.byond.com/docs/ref/skinparams.html>; webclient
  `.dmf`/`.dms`: <https://www.byond.com/docs/ref/webclient.html>
- BYOND 515 release notes (byondapi, `-console`, `memory`, `map-threads`,
  editor behaviours): <https://www.byond.com/docs/notes/515.html>
- BYOND 516 release notes (build numbers, `DreamMaker` CLI bugfix):
  <https://www.byond.com/docs/notes/516.html>
- `world.Reboot`, `world.OpenPort`, `world.Export`, `world.Topic`:
  <https://ref.dm-lang.org/world/proc/Reboot>,
  <https://ref.dm-lang.org/world/proc/OpenPort>,
  <https://ref.dm-lang.org/world/proc/Export>,
  <https://ref.dm-lang.org/world/proc/Topic>,
  <https://ref.dm-lang.org/world/var/port>
- Publishing games, hub entries, `hub_password`, Hub Version:
  <https://www.byond.com/developer/articles/publish>
- Canonical production deployment pattern (dual daemon, port swap, compile-job
  locks, watchdog):
  <https://tgstation.github.io/tgstation-server/architecture.html>

Repository files read for the Craft++ side: `CraftBuild.cs`, `IdeFileFlow.cs`,
`BuiltinProcs.Stubs.cs` (`ExecuteReboot`), `HeadlessProgram.cs`,
`RELEASE_PIPELINE.md`, `ONLINE_UPDATE_CHECK.md`, `build_and_upload.sh`,
`BYOND_DM_PARITY_MATRIX.md`, `LANGUAGE_FUNCTIONAL_AUDIT.md`,
`.github/workflows/build.yml`.

## 7. Parity changelog (verified runs)

Every row below was applied in place on the VPS and re-checked afterwards. "Smoke" means
the assertion runs in `--parity-smoke` and fails the run; "compile" means the code builds
but has not been exercised (no Windows desktop is available on the host).

| # | Gap closed | Change | File | Verified by |
|---|---|---|---|---|
| 1 | `world.Reboot()` restarted in place instead of rebuilding the artifact | `RebootRequested` event + off-stack reload that reopens the same port | `Interpreter.cs`, `BuiltinProcs.Stubs.cs`, `WorldHost.cs` | smoke + compile |
| 2 | `#pragma push`/`pop` dropped the named-warning policy | warning policy added to the pragma snapshot | `Preprocessor.cs` | smoke |
| 3 | `#pragma push`/`pop` dropped the multiple-include policy | `AllowMultipleIncludes` added to the snapshot | `Preprocessor.cs` | smoke |
| 4 | `#pragma warn <Name>` ignored `ignore`/`error` state | named warnings routed through the active policy | `Preprocessor.cs` | smoke |
| 5 | `world.Topic()` unimplemented | `WorldTopic("ping")` reports players+1, unknown topics 0 | `BuiltinProcs.cs` | smoke |
| 6 | Warnings built but never surfaced | warnings listed in the build diagnostics panel, double-click navigates | `MainWindow.xaml.cs` | compile |
| 7 | `__MAIN__` undefined everywhere | defined only in the main file and masked while includes run | `Preprocessor.cs` | smoke |
| 8 | No `.dme` reader at all | `DmeProject` parses `FILE_DIR`, ordered includes, missing files, and rewrites the include block | `DmeProject.cs` (new) | smoke |
| 9 | Compile unit came from an alphabetical directory walk | compile order follows the `.dme` include list | `MainWindow.xaml.cs` | smoke (parser) + compile |
| 10 | Main file identity was a synthetic path, so `__MAIN__` could never be true in real code | `RootFileName` is the real `.dme` | `MainWindow.xaml.cs` | compile |
| 11 | Open Project could not browse to a `.dme` | `.dme` added as the primary filter | `MainWindow.xaml.cs` | compile |
| 12 | `Refresh` advertised `F5`, which is bound to Compile | duplicate gesture text removed | `MainWindow.xaml` | compile |

### Verification actually run

- `dotnet build -f net8.0` — 0 errors
- `dotnet build -f net8.0-windows -p:EnableWindowsTargeting=true` — 0 errors
- `--parity-smoke` — PASS, 182/182 globals, 279/279 type fields, 162/162 type procs, plus the behavioral assertions for rows 1-5, 7, 8
- `CraftPlusPlus.Tests` — 874 passed, 0 failed
- `CraftPlusPlus.Windows.Tests` — **could not run**: host lacks `Microsoft.WindowsDesktop.App 8.0.0`; this is an environment limit, not a code failure

### Still open after this changelog

- `.dme` includes that sit above the project root still fail the outside-the-project guard, though Dream Maker permits them
- include *membership* is not enforced; unlisted files still compile, just after the listed ones
- the project tree is built from the filesystem, so `FILE_DIR` folders that are empty on disk do not appear
- rows marked "compile" have not been clicked through on Windows
