Symptom

Phase-3 spike on whether server-side capabilities could run inside the Compose Multiplatform app (desktop / Android / iOS). The original framing (“embed Ktor server in JVM desktop”) didn’t survive contact with the actual target — iOS is Kotlin/Native, not JVM, and Ktor server does not target Kotlin/Native at the version pinned in gradle/libs.versions.toml.

Root cause

Two assumptions in the original framing were wrong:

  1. The relevant runtime is JVM. Reality: three runtimes — JVM (desktop + Android), Kotlin/Native (iOS), and (best-effort) wasmJs.
  2. “Local engine” means “the same code path the Pi runs.” Reality: the server module pulls jakarta.mail, Paho MQTT, jSerialComm, Pi4J gRPC, Exposed, H2, and ProcessBuilder-based Lambda sandboxing. None of those compose with Kotlin/Native; several (Lambda especially) don’t compose with anything but desktop Linux.

Fix

docs/spike-local-engine.md — capability inventory, per-platform feasibility matrix, three module-layout options, and a conditional go recommendation (Option C: commonMain processor subset on top of #249’s LocalNodeStore; reserve a desktop-only server-embedded wrapper for a follow-up gated on a recipe that needs it). No production code.

Prevention

For future “embed X in the app” spikes — start by enumerating which target runtimes are in play and which JVM-only libraries the relevant server code imports. The capability inventory in §1 of the spike doc is the template. This catches the “JVM-only by accident” trap (e.g., assuming Ktor server is multiplatform because Ktor client is) before any plan gets drawn up.