Game guide · source of truth
Ledger

M0-11D

One-simulation spike part D: zoen-sim-ffi Windows + iOS built (recorded not tested), M0-11 result into ADR-029

← Ledger

donestatus · M0
10✓ 2✗tests passed / failed
0tokens · 11 min
4evidence files · 11 kB

Evidence

From logs/evidence/M0-11D/. Click a thumbnail for the full image.

Logs and data (4)

spike-report.md · 4 kB · open
# Spike M0-11: one simulation (ADR-029) — report

The Rust `zoen-sim` step as a C ABI plugin (`crates/zoen-sim-ffi`) inside the Unity client. Golden check: scenario
`walk_eight_directions` from `packages/sim-golden/vectors.json`, final hash `bb46012ea5aaaebf`, every tick compared.
Data: `spike-report.json`; per-target build reports `plugin-*.json` in each `logs/evidence/M0-11*` folder.

| Target | Result | Plugin | Step cost (median, ns/tick: 1 / 5,000 movers) |
|---|---|---|---|
| macOS (Apple M3 player) | **pass** — hash match, all scenarios | dylib arm64 406,288 B | 108 / 333,200 |
| Android (nubia NX709S, APK) | **pass** — 4 tiers, hash match | .so arm64 316,552 B (stripped, 16 KB aligned) | 54.5 / 149,075–158,175 |
| Web (headless Chrome) | **pass** — 0 console errors, hash match | static archive 3,662,566 B; Web build +37,947 B (+0.32%) | 70–100 / 160,000–215,000 (timer-quantized) |
| iOS (aarch64-apple-ios) | **built, not tested** (ADR-032) | static archive 2,333,096 B (debug stripped) | — |
| Windows (x86_64-pc-windows-msvc) | **staticlib built; DLL blocked**, not tested | .lib 3,701,330 B; no DLL | — |

5,000-mover costs include the C# input fill; all stay under 0.35 ms of a 16.7 ms frame.

## Toolchains
Unity 6000.3.25f1 · rustc 1.99.0 (LLVM 23) · Android NDK r27c (bundled) · Emscripten 3.1.39-git with LLVM 17 (bundled) ·
Xcode 26.6, iPhoneOS SDK 26.5, minimum iOS 15.0.

## Web specifics
- Emscripten feature rewrite: rustc's objects list the LLVM 20+ `target_features` names `bulk-memory-opt` and
  `call-indirect-overlong`; the bundled LLVM 17/Binaryen rejects them, so `tools/sim/build-plugin.mjs web` drops them
  (implied by `bulk-memory` and `reference-types`, which stay). Re-check on every rustc or Unity upgrade.
- Browser floor: Chrome 95, Firefox 100, Safari 15.2 (the precompiled std keeps legacy wasm EH pads, bulk memory and
  reference types). Lowering it needs `-Zbuild-std` with `target-cpu=mvp` (nightly flags).
- `panic=abort` on the Web: no `catch_unwind`, so the plugin relies on its panic-free code (clippy denies indexing/panic).

## iOS (recorded not tested)
`node tools/sim/build-plugin.mjs ios`: staticlib at iOS 15.0, every member iOS platform, 9 header exports, needs only
`-lSystem -lc -lm`; the C ABI smoke links with the iPhoneOS SDK (not run: no device or simulator target here).
229 of 375 members (Rust's prebuilt std/compiler_builtins) carry embedded LLVM 23 bitcode that Xcode's LLVM cannot
parse; the linker drops it (the linked smoke has no `__LLVM` segment). Installed at
`Assets/Zoen/Plugins/iOS/libzoen_sim_ffi.a` (iOS player only); iOS builds get `ZOEN_SIM_STATIC`. The Unity Xcode
export and an unsigned `xcodebuild` are M0-11D2.

## Windows (recorded not tested)
`node tools/sim/build-plugin.mjs windows`: the staticlib builds (COFF x86-64, 9 exports). The DLL does not link with
rust-lld: it needs the Windows SDK import libraries (kernel32, ntdll, userenv, ws2_32, dbghelp) and the MSVC CRT
(msvcrt, vcruntime, ucrt). Getting them means accepting Microsoft's licence (owner): Visual Studio Build Tools on a
…
plugin-ios.json · 2 kB · open
{
  "what": "zoen-sim C ABI static library for iOS arm64 (M0-11D)",
  "status": "built; recorded not tested (ADR-032)",
  "finished": "2026-10-10T20:46:26.700Z",
  "rustc": "rustc 1.99.0 (b940084d7 2026-09-28)",
  "target": "aarch64-apple-ios",
  "deploymentTarget": "15.0",
  "xcode": "Xcode 26.6",
  "profile": "plugin (release, lto, codegen-units 1, strip debuginfo) + strip -S",
  "platforms": [
    "2"
  ],
  "minos": [
    "15.0"
  ],
  "nativeLibs": [
    "-lSystem",
    "-lc",
    "-lm"
  ],
  "exports": [
    "zoen_sim_abi_version",
    "zoen_sim_create",
    "zoen_sim_destroy",
    "zoen_sim_push_inputs",
    "zoen_sim_read_actors",
    "zoen_sim_read_events",
    "zoen_sim_spawn",
    "zoen_sim_state",
    "zoen_sim_step"
  ],
  "embeddedBitcodeMembers": 229,
  "cSmokeLink": {
    "linked": true,
    "sdk": "26.5",
    "platform": "IOS",
    "minos": "15.0",
    "bytes": 369152,
    "keepsBitcode": false,
    "ran": false,
…
plugin-windows.json · 2 kB · open
{
  "what": "zoen-sim C ABI for Windows x86_64 (M0-11D)",
  "status": "staticlib built; DLL blocked on the MSVC CRT and Windows SDK import libraries (Microsoft licence, owner); recorded not tested (ADR-032)",
  "finished": "2026-10-10T20:46:38.415Z",
  "rustc": "rustc 1.99.0 (b940084d7 2026-09-28)",
  "target": "x86_64-pc-windows-msvc",
  "profile": "plugin (release, lto, codegen-units 1, strip debuginfo)",
  "nativeLibs": [
    "kernel32.lib",
    "ntdll.lib",
    "userenv.lib",
    "ws2_32.lib",
    "dbghelp.lib",
    "/defaultlib:msvcrt"
  ],
  "objectFormats": [
    "coff-x86-64",
    "COFF-import-file"
  ],
  "exports": [
    "zoen_sim_abi_version",
    "zoen_sim_create",
    "zoen_sim_destroy",
    "zoen_sim_push_inputs",
    "zoen_sim_read_actors",
    "zoen_sim_read_events",
    "zoen_sim_spawn",
    "zoen_sim_state",
    "zoen_sim_step"
  ],
  "staticlib": {
    "path": "target/x86_64-pc-windows-msvc/plugin/zoen_sim_ffi.lib",
    "bytes": 3701330,
    "sha256": "c3b949ad0b1cd520105bb0c28ed7f8cf76cf98001c8f53fe4e985b5a29cd1bf6",
    "members": 291
  },
  "dll": {
    "status": "blocked",
    "linker": "rust-lld (lld-link flavour)",
    "missingImportLibs": [
…
spike-report.json · 4 kB · open
{
  "task": "M0-11D",
  "spike": "M0-11 one simulation (ADR-029)",
  "finished": "2026-10-10T20:49:40.727Z",
  "golden": {
    "scenario": "walk_eight_directions",
    "finalHash": "bb46012ea5aaaebf",
    "source": "packages/sim-golden/vectors.json"
  },
  "toolchain": {
    "unity": "6000.3.25f1",
    "rustc": "rustc 1.99.0 (b940084d7 2026-09-28)",
    "androidNdk": "r27c (27.2.12479018, bundled with Unity)",
    "emscripten": "3.1.39-git (bundled with Unity, LLVM 17 fork)",
    "xcode": "Xcode 26.6",
    "iphoneosSdk": "26.5",
    "iosDeploymentTarget": "15.0"
  },
  "targets": [
    {
      "target": "macOS",
      "rust": "aarch64-apple-darwin",
      "result": "pass",
      "tested": true,
      "evidence": "logs/evidence/M0-11/",
      "binary": {
        "kind": "dylib arm64",
        "bytes": 406288
      },
      "stepNsPerTick": {
        "movers1": 108,
        "movers5000": 333200
      },
      "note": "macOS player (Apple M3), finalHash match, allMatch"
    },
    {
      "target": "Android",
      "rust": "aarch64-linux-android",
      "result": "pass",
      "tested": true,
…

Tests

fail build-plugin ios (staticlib, C smoke linked with iPhoneOS SDK, installed) · 4.9 s · raw log$ node tools/sim/build-plugin.mjs ios
pass build-plugin ios (staticlib, C smoke linked with iPhoneOS SDK, installed) · 8.6 s · raw log$ node tools/sim/build-plugin.mjs ios
fail build-plugin windows (staticlib; DLL link attempt without MSVC libs) · 0.8 s · raw log$ node tools/sim/build-plugin.mjs windows
pass build-plugin windows (staticlib; DLL link attempt without MSVC libs) · 0.9 s · raw log$ node tools/sim/build-plugin.mjs windows
pass Unity EditMode (iOS/Windows import rules, iOS static define) · 20.0 s · raw log$ node tools/unity-run.mjs editmode
pass data tests · 7.5 s · raw log$ pnpm data:test
pass zoen-sim cargo tests + clippy · 14.0 s · raw log$ pnpm sim:test
pass Zoen.Core dotnet build + xunit · 2.5 s · raw log$ pnpm core:test
pass docs lint + index · 0.2 s · raw log$ pnpm docs:lint
pass wiki typecheck · 2.2 s · raw log$ pnpm --filter @zoen/wiki typecheck
pass wiki production build · 11.9 s · raw log$ pnpm wiki:build
pass wiki e2e (changed specs) · 1.3 s · raw log$ pnpm --filter @zoen/wiki exec playwright test --only-changed

Notes

2026-10-10 20:50 UTC · Roadmap: roadmap.json tracks no task or gate state (only status=replaced), so nothing to set; done-state comes from the task log. ADR-029 + ADR-003 status line updated.

2026-10-10 20:51 UTC · Done; M0-11 complete. rustup targets aarch64-apple-ios + x86_64-pc-windows-msvc (owner approval 2026-10-10). Xcode 26.6 is now installed (iPhoneOS SDK 26.5; CONTINUE_HERE said absent). build-plugin.mjs ios: staticlib at iOSTargetOSVersionString 15.0, strip -S 5,890,424 -> 2,333,096 B (375 members, all platform iOS minos 15.0, needs -lSystem -lc -lm, 9 exports); C smoke linked with xcrun --sdk iphoneos clang (not run: no device/sim target, ADR-032). 229 std/compiler_builtins members embed LLVM 23 bitcode that Apple nm (LLVM 21) cannot parse: nm --no-llvm-bc; the link drops it (smoke has no __LLVM segment). Installed Assets/Zoen/Plugins/iOS/libzoen_sim_ffi.a with a hand-written iOS-only .meta (avoids the default-meta first import seen in C2). build-plugin.mjs windows: staticlib 3,701,330 B (COFF x86-64 + raw-dylib import members, 9 exports); DLL via rust-lld blocked: missing kernel32/ntdll/userenv/ws2_32/dbghelp.lib + msvcrt.lib (MSVC CRT, Windows SDK: Microsoft licence) -> owner-licence pending line in logs/reviews.jsonl; ZOEN_WIN_LIBS hook passes lib dirs once allowed. No Windows player build (no DLL). SimPluginImport: IOSPlugin/WindowsPlugin + ApplyIOS (iOS only, no editor) / ApplyWindows (StandaloneWindows64 only, CPU x86_64, no editor), StaticLibraryFor(target); Build.PlayerDefines adds ZOEN_SIM_STATIC for WebGL and iOS when their .a exists. EditMode 81/81 (+IOSPluginImportsForTheIOSPlayerOnly, +WindowsPluginImportsForTheWindows64PlayerOnly on a stand-in .dll, OnlyTheWebBuild... renamed OnlyTheStaticLibraryBuildsGetTheStaticSimDefine). Evidence logs/evidence/M0-11D/: plugin-ios.json, plugin-windows.json, spike-report.md/.json. ADR-029 spike result (confirmed with qualification; open risks Windows licence/no machine, iOS not run, Emscripten LLVM gap, Web floor). verify --changed green. Optional M0-11D2: Unity iOS Xcode export (needs Build.IOS + unity-run build ios export path) and unsigned xcodebuild now that Xcode exists.