[workspace] resolver = "2" members = ["crates/*"] [workspace.package] version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" authors = ["sam "] # Shared pins live here; promote a dep the moment two crates pin the same version (the policy # since day one, enacted at the 0530 debt sweep). Per-crate feature additions stay in the crate. # `image` deliberately stays per-crate: its default-features/feature sets differ per consumer, # and a workspace default-features choice can't be subtracted from downstream. [workspace.dependencies] anyhow = "1.0.102" bevy = "0.18.1" # The render app's raw GPU handles (the WOW_GPU_MS meter's query set): bevy 0.18 does not wrap # wgpu's QuerySet family, so the meter reaches for the same wgpu the workspace already builds. wgpu = "27" clap = { version = "4.6.1", features = ["derive"] } sha1 = "0.10.6" # The WoW format + protocol stack is fully in-repo (decision 0021), so there are no warcraft-rs / # wow_messages crates (or forks of them) anywhere in the tree. That is still true and is why this # section stood empty for the project's whole life. # # The one entry below is not a fork of a WoW crate at all. `lua-src` compiles the Lua the client's # addon VM runs on, and the 1.12 corpus needs one opcode that Lua 5.1 deleted — the iterator-less # generic-for (`for k, v in someTable do`), which 183 of 218 corpus addons are reached by and which # is the first session-start error for 60 of them. It is an OPCODE, so no layer above the VM can # reach it: not a library function, not a global, not a metamethod. # # The fork is currently BYTE-IDENTICAL to upstream's 5.1.5 sources, and is landed that way on # purpose: the pipeline is proven transparent before the behavioural payload goes into it, so that # when the suite moves, the patch is the only thing that could have moved it. The payload waits on # an RE answer about what the real client's own Lua does — stock Lua 5.0 is corroboration, not the # authority. `third_party/lua-src/BENILLA.md` has the current state and the verifying command. [patch.crates-io] lua-src = { path = "third_party/lua-src" } # Optimize *dependencies* even in dev builds. avian/parry collision math (and wgpu/bevy render) is # unusably slow at opt-level 0 — a plain `cargo run` crawls to <1 fps once physics is doing real work. # opt-level 3 on deps (the standard Bevy fix) makes debug builds playable while our own crates stay # lightly optimized for fast incremental rebuilds. One-time cost: deps recompile optimized the first time. [profile.dev.package."*"] opt-level = 3 # Our own crates at opt-level 1, not 0: Bevy's generic hot paths (material specialization scans, # query par_for_each closures) monomorphize INTO our crate, so at opt 0 they run at debug codegen # speed over every resident entity — measured at Stormwind as the difference between ~45 fps and a # pinned 60 (decision 0362). Warm incremental rebuild cost measured at ~zero. NB: FPS probe numbers # in decisions ≤ 0361 were taken at opt 0 and are not comparable with post-0362 probes. [profile.dev] opt-level = 1 # No debuginfo trimming: `debug = "line-tables-only"` was A/B-measured (decision 0192) at zero # recurring win on this stack (macOS unpacked split-debuginfo; sccache; fast ld) — not worth # invalidating every warm target and the sccache cache for. # Shipping-grade optimization, A/B-graded at the pin (decision 0736): −1.0 cpu_ms (−5 %) vs # default release, flat at the empty-map and bare-Bevy floors. The campaign keeps grading on # default `release` — same-day A/B is the law, and fat LTO's link time would tax every # iteration for a constant offset. Build with `--profile ship` for actual releases (add # `RUSTFLAGS=-Ctarget-cpu=native` for a machine-local binary; not set here — it isn't portable). [profile.ship] inherits = "release" lto = "fat" codegen-units = 1 # The director's play loop (decision 1157): `release` plus incremental compilation. `benilla-app` is one crate of # ~243k lines, and release is non-incremental by cargo's default, so a one-line edit re-optimizes # all of it — measured 2m47s (43s frontend, ~121s LLVM at opt-level 3) against a 1.8s stamp rebuild # and a 2.5s no-op. Incremental caches both halves per codegen unit, so an edit pays for what it # touched. Cargo applies `incremental` to workspace members ONLY (verified: `target/debug/incremental` # holds our 16 crates and zero registry deps), so the ~760 dependencies stay non-incremental and # sccache-cacheable — 0192's wrapper and the cold-slot build are untouched. # # Why a separate profile rather than flipping `release`: incremental raises the codegen-unit count # and drops cross-unit inlining, which is a real codegen difference. The FPS campaign grades on # default `release` (0736) and same-day A/B is the law, so the graded profile must not quietly # change under it. Run it as `cargo play` (the alias in `.cargo/config.toml`). [profile.play] inherits = "release" incremental = true # ThinLTO OFF, and it is not a performance choice -- it is the fix for rustc #86049. `release` # implies thin-LOCAL LTO (ThinLTO across a crate's own codegen units), which promotes each CGU's # internal anonymous constants to external symbols named `anon..N.llvm.`. Under # `incremental` some CGUs come back from the cache carrying names minted in an earlier compile, # so a promoted reference finds no definition and `cc` fails with "symbol(s) not found for # architecture arm64" -- an intermittent link failure with no source-level cause, cleared only by # a full rebuild. Measured on the 2026-08-29 occurrence: 7 poisoned CGUs in `benilla-formats`, 48 # unresolved symbols. `lto = "off"` disables the promotion step entirely (verified: the play rlib # goes from 381 undefined `anon.*.llvm.*` symbols to 0). `release` and `ship` are UNTOUCHED -- they # are non-incremental, cannot hit this, and stay the graded profiles (0736). Decision 1698. lto = "off"