Summary
EntropiaOrme v0.1.0 ran as two processes: a native shell, and a bundled Python backend the shell spoke to over local HTTP. The backend was ported to Rust by AI agents (Fable 5 and Opus 4.8), one service at a time behind an equivalence gate: recorded and scripted play sessions were replayed through both implementations, and a ported service landed only by reproducing the Python backend’s outputs byte for byte. Since v0.2.0 the app is one Rust binary; the installer is about 70% smaller (181 MB to 54 MB, per the releases page) and live data appears in about 0.8 seconds instead of 3.5.
Problem statement
In the first release, the analytics backend was written in Python and ran, together with a bundled Python runtime, as a second process beside the native shell. That process had three costs: the runtime dominated the installer, live data waited on a second program starting up, and the socket between the halves added failure modes of its own. Therefore, the backend was moved into the shell’s own language.
The equivalence gate
The risk in the port was output slightly different from the Python backend’s, so the current behaviour was pinned down in a checkable form before any of it changed: play sessions are replayed through the full pipeline in the game’s own chat.log format, and everything observable at the far end is captured into committed reference files that a ported service has to reproduce. Where the reference files did not reach (some database tables had none), the gap was recorded rather than assumed covered, and those surfaces were watched through a period of real play before the old backend was removed.
Porting with agents
With the gate in place, the porting was orchestrated with AI agents (Fable 5 and Opus 4.8), one service at a time. The replay harness is what made the orchestration workable: an agent could replay the sessions, compare its port’s output against the reference files, and keep correcting itself until they matched, so the work could run in long uninterrupted spans; the longest single run had Fable 5 working for over 32 hours.
The reference files did not cover everything. Two defects were caught by manual testing, both on uncovered surfaces: a settings file with two writers, and a keyboard listener that had collapsed two independent hooks into one. Each was diagnosed against candidate causes by independent agents and settled by a manual reproduction. When the last service was ported, the socket was removed.
The pure-Rust OCR experiment
One native dependency remained after the migration: the ONNX runtime that executes the OCR model. A reimplementation in candle, a Rust machine-learning framework, was proven faithful (across the 594-image test set from the OCR benchmark, the two implementations agree on every cell), but it measured about four times slower on CPU, has no GPU route matching the DirectML one the app uses, and pulls in a C library transitively. It is parked, with its equivalence proof, on a public branch.
Results
The two architectures are compared below, measured once the port had settled.1
| Python backend (v0.1.0) | Rust backend (v0.2.0) | |
|---|---|---|
| Release files | ||
| Installer | 181 MB | 54 MB |
| Portable package | 181 MB | 52 MB |
| Cold start, from process start | ||
| App window visible | 372 ms | 392 ms |
| Backend ready | 3,054 ms | 794 ms |
| Live data painted | 3,535 ms | 802 ms |
| Idle memory, by component | ||
| Native shell | 32.6 MiB | 137.2 MiB |
| Python backend (2 processes) | ~192 MiB | none |
| WebView2 renderers | ~550 MiB | ~547 MiB |
| Whole app | 775 MiB | 684 MiB |
| CPU usage while tracking a hunt | ||
| Mean | 0.2% | 0.0% |
| 95th percentile | 0.8% | 0.1% |
| Peak | 1.5% | 0.3% |
Conclusion
EntropiaOrme has been one Rust binary since v0.2.0, and v0.2.1 retired the Python implementation entirely; the behaviour it defined remains in the test suite as byte-for-byte assertions. The porting itself, run behind the gate, took about two weeks; the gate and its recorded sessions were built over the weeks before.
Footnotes
-
Installer and portable sizes are computed from the published release files; the remaining figures are instrumented rebuilds measured on Windows 11 (12 logical cores) under light background load: cold start over six runs, idle memory as the median of five samples after settling, and the tracking measurement a recorded 150-line hunt replayed at real cadence (about 229 seconds). The figures compare the two architectures rebuilt with current dependencies, not the historic v0.1.0 binary as released. OCR per-scan latency and the game’s frame rate were not measured. ↩