diff --git a/Cargo.toml b/Cargo.toml index 432a4942..9ff6207c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,33 +8,18 @@ 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. -# **Lint policy** (decision 2266 §C4). `too_many_arguments` is a readability lint for plain -# functions; on a Bevy system the parameter list IS the scheduler's dependency declaration, and -# a system that reads eight resources has eight parameters by construction. The lint had fired -# 364 times in this workspace and been allowed 364 times, 281 of them on systems — a lint whose -# every verdict is overridden is not a gate, it is a tax on adding a system. Allowed once here; -# the per-site attributes are gone. `type_complexity` stays on: it fires on shapes a type alias -# or a `SystemParam` bundle genuinely fixes. +# A version two crates share is pinned in `[workspace.dependencies]`; feature additions stay per +# crate. `image` stays per-crate: its consumers differ on default features, and a member cannot +# turn off default features that a workspace entry enables. +# `too_many_arguments` is off: a Bevy system's parameter list is its dependency declaration. [workspace.lints.clippy] too_many_arguments = "allow" [workspace.dependencies] anyhow = "1.0.102" -# bevy's `default` is `["2d", "3d", "ui"]`, and every one of those three pulls `audio` -# (= `bevy_audio` + `vorbis`) — so a default bevy compiles rodio, a second cpal, a second ALSA -# binding and an ogg/vorbis decoder into a client that mixes through kira and has had bevy's -# `AudioPlugin` disabled at boot since 0530. This spells the same `default` out with `audio` -# taken away: `2d`/`3d`/`ui` decomposed into the parts they are made of, which is the whole -# union of the three minus that one entry (decision 1932 has the expansion, verified against a -# before/after feature tree). Nothing else in the graph asks for it — avian3d, bevy_egui and -# bevy_transform_interpolation all take bevy with `default-features = false`. -# -# If a future bevy needs another member, add it here by name; do not reach back for `2d`/`3d`/ -# `ui`, which would quietly bring the audio stack with it. +# bevy's default features spelled out without `audio`: `2d`, `3d` and `ui` each pull `bevy_audio` +# and `vorbis`, and the client mixes through kira. Add a feature by name, never `2d`/`3d`/`ui`; a +# plugin that takes bevy with its default features brings the audio stack back too. bevy = { version = "0.18.1", default-features = false, features = [ "default_app", "default_platform", @@ -45,88 +30,44 @@ bevy = { version = "0.18.1", default-features = false, features = [ "scene", "picking", ] } -# 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. +# For the `WOW_GPU_MS` meter's query set, which bevy 0.18 does not wrap; must match bevy's wgpu. 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 benilla's Lua has to accept EXACTLY the grammar the 1.12.1 client's Lua -# accepts — no more and no less. The hunks — `third_party/lua-src/BENILLA.md` lists them — all byte-read out of the client's own parser and VM: -# they restore what 5.1 removed (the iterator-less generic-for `for k, v in someTable do`, which -# 183 of 218 corpus addons are reached by; nesting long strings; the constructor's compat -# semicolon) and delete what 5.1 added (`...` as an expression, `#`, `%`). Both directions are -# below the reach of any layer above the VM — an opcode and a grammar are not a library function, -# a global, or a metamethod — and the corpus ASKS about the second direction directly: 170 -# `loadstring` sites compile a vararg expression purely to find out which interpreter they are on. -# -# The fork landed BYTE-IDENTICAL to upstream's 5.1.5 sources on purpose: the pipeline was proven -# transparent before any behavioural payload went into it, so when the suite moved, the patch was -# the only thing that could have moved it. `third_party/lua-src/BENILLA.md` has the current state, -# the per-hunk byte evidence and the verifying command (decisions 1215, 1315, 2101). +# lua-src builds the addon VM's Lua 5.1.5, patched to accept exactly the 1.12 client's grammar; +# the hunks and the command that checks them: `third_party/lua-src/BENILLA.md`. [patch.crates-io] lua-src = { path = "third_party/lua-src" } -# kira 0.12.1 with one patch: spatial gains and the volume tween evaluated per CHUNK and -# interpolated, not per frame (decision 1945; `third_party/kira/BENILLA.md`). +# kira 0.12.1, patched to compute spatial gains and the volume tween per output chunk and +# interpolate them, not per sample frame (`third_party/kira/BENILLA.md`). kira = { path = "third_party/kira" } -# 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. +# Dependencies at opt-level 3 in dev: at opt-level 0, avian/parry collision drops a run to <1 fps. [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. +# Our crates at opt-level 1: Bevy's generic hot paths monomorphize into them, and at opt-level 0 +# Stormwind drops from a pinned 60 fps to ~45; the warm incremental rebuild cost is ~0. [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. +# No debuginfo trimming: `debug = "line-tables-only"` measures no recurring win on macOS + sccache. -# 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). +# The shipping build (`--profile ship`): fat LTO measures -1.0 cpu_ms (-5 %) against `release`, +# which stays the measured profile because fat LTO's link time would tax every iteration. +# `-Ctarget-cpu=native` is not set: it is not 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 -# hundreds of thousands of lines (243k when this was measured), 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 the workspace members 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`). +# `release` plus incremental, run as `cargo play`: under `release` a one-line edit to +# `benilla-app` costs 2m47s. Incremental applies to workspace members only, so dependencies stay +# sccache-cacheable; it changes codegen, so it lives here and not in the measured `release`. [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. +# Not for speed: under `incremental`, thin-local LTO leaves promoted `anon.*.llvm.*` symbols +# unresolved and the link fails intermittently (rustc #86049). lto = "off" diff --git a/crates/benilla-app/Cargo.toml b/crates/benilla-app/Cargo.toml index 67ef8cc8..95d0cf8b 100644 --- a/crates/benilla-app/Cargo.toml +++ b/crates/benilla-app/Cargo.toml @@ -9,154 +9,79 @@ description = "The Bevy app as a library: everything but the build-id stamp, whi workspace = true [features] -# **The dev/player seam** (decisions 0026 + 1173). Default-ON, so every ordinary `cargo run`, -# capture, probe and gate builds exactly what it built before. `--no-default-features` compiles -# the instruments — the debug panel, the perf HUD, the inspector, the capture harness and the -# probe fleet — physically OUT: not dormant behind a runtime flag, absent. That is the whole -# requirement a player client has of them, and a runtime toggle cannot meet it. -# -# The rule the seam enforces is one-directional: **dev may see anything; nothing may depend on -# dev.** It is enforced by `cargo build -p benilla --no-default-features` in `scripts/gates.sh`, -# not by anyone remembering it — 0026 adopted the rule in June 2026 with no failing build behind -# it, and twenty-four couplings had accumulated by August (1173). +# `dev` compiles in the instruments: the debug panel, perf HUD, inspector, capture harness and +# probes. Nothing may depend on it; `scripts/gates.sh` builds `benilla` with no default features. default = ["dev"] -# -# The three benilla crates below are taken with `default-features = false` and their `dev` -# re-exported here (1175). Their `dev` is default-on too, so without the round trip a -# `--no-default-features` build gets the feature back through unification — and the binary -# carries the build machine's source-tree path after all. Same trap as the shim's, one level down. +# `benilla-assets`, `-formats` and `-world` come in without default features and their `dev` is +# forwarded here: it is on by default in each, so unification would put it back in a player build. dev = ["benilla-assets/dev", "benilla-formats/dev", "benilla-world/dev", "dep:bevy_egui"] -# Opt-in Tracy profiling: `cargo run --features tracy` streams per-system `info_span!` markers (on the -# hot systems) + render-pass CPU timings to a Tracy capture (decision 0026 — the dev/player seam; -# a `docs/howto/running.md` this once cited never landed). tracy = ["bevy/trace_tracy"] -# Opt-in Chrome-trace profiling: `cargo run --features trace_chrome` writes a `trace-.json` of -# every system's per-run span next to the working dir. Tracy's offline twin — it needs no GUI and no -# live capture, so a per-system cost question is answerable from a terminal (and from a run someone -# else recorded). Its readers: `scripts/tracesum.py` (per-span totals), `scripts/framecost.py` -# (the per-frame cost ledger, 0718) and `scripts/tracebands.py` (a window band-mapped into -# replaceable units, 1413/1414). +# `--features trace_chrome` writes every system's per-run span to `trace-.json` in the cwd. trace_chrome = ["bevy/trace_chrome"] [dependencies] anyhow.workspace = true -# OS clipboard access for the UI EditBox copy/cut/paste chords (chat input). Already in the tree via -# bevy_egui; pinned to the same 3.x so there's one copy. Read on the main thread (the UI key feed is -# a NonSend system) — required for the macOS NSPasteboard path. Covers macOS, Windows, and Linux/BSD -# under X11; the Wayland backend is `smithay-clipboard` below (decision 0702). +# The EditBox clipboard chords, read on the main thread as macOS NSPasteboard requires; Wayland +# goes through `smithay-clipboard`. The 3.x bevy_egui uses, so the graph has one copy. arboard = "3" benilla-ui = { path = "../benilla-ui" } bevy.workspace = true wgpu.workspace = true -# Optional: the dev overlays are its only consumers (the panel, the perf pill, the inspector -# card), so a player build does not link it at all (`dev` feature, decision 1173). bevy_egui = { version = "0.39", optional = true } -# Zero-copy POD→bytes for the shared light storage buffer (one per-frame write_buffer). Already in -# the tree transitively; pinned to the same version as the dev-dep below. bytemuck = { version = "1", features = ["derive"] } -# `f16` decode for the booth-target dump (`WOW_BOOTH_DUMP`): the booth render targets are -# `Rgba16Float` (decision 0804) and the PNG wants display bytes. Already in the tree via -# wgpu/bevy_image; declared so the call site is an honest dependency. +# `f16` decode for the `WOW_BOOTH_DUMP` dump of the `Rgba16Float` booth render targets. half = "2" -# The shipped FrameXML tree, compiled into the binary (decision 1175 §2): 61 files, ~2.8 MB, so the -# client cannot boot without its interface on a machine that has never seen our source. A proc -# macro plus a no-dependency runtime shim — it adds nothing to the graph at runtime, and it is the -# crate everyone uses for this. `assets/ui` is OUR content (MIT/Apache), not Blizzard's. +# Compiles `assets/ui` into the binary, so the interface loads on a machine without the source. include_dir = "0.7" -# The 1.12 chat filters are PCRE over shipped DBCs (decision 2077; `text_filter`): 2289 profanity -# expressions and 28 spam ones, compiled once at startup and run over every chat line. `RegexSet` is -# exactly the shape that needs — one automaton over the whole list for the "can anything match at -# all" pass — and the crate is already in the tree transitively. +# The 1.12 chat filters (`text_filter`): the DBCs' 2289 profanity and 28 spam patterns, with one +# `RegexSet` for the any-match pass over every chat line. regex = "1" -# `getrusage` — whole-process CPU time (all threads), the perf probes' `cpu_ms`/`cpu_pct` metric -# (`perf::process_cpu_secs`). Wall-clock fps is unusable as a regression instrument on a machine -# running parallel sessions' builds; CPU-per-frame is, and it is also the number the Mac report -# is about ("250 % CPU at 59 fps"). Was dev-only; since 1857 the output backend needs it in every -# build too (`mach_absolute_time`, the host clock its meters read; `thread_policy_set`, the render -# thread's realtime policy). +# `getrusage` for the perf probes' process CPU time; `mach_absolute_time` and `thread_policy_set` +# for the audio output's meter clock and its render thread's realtime policy. libc = "0.2" -# Resample varying-size layer BLPs to a uniform size for the terrain texture array; `png` so we can -# encode the cursor image into data an NSImage can load (macOS hardware cursor). +# PNG encoding only: the macOS hardware cursor's NSImage data and screenshots. image = { version = "0.25", default-features = false, features = ["png"] } -# The net↔ECS bridge: a background IO thread streams typed `SessionEvent`s to the ECS over a -# channel, and outbound `ClientCommand`s back. crossbeam's Sender/Receiver are `Send + Sync + Clone` -# (std's mpsc Sender is `!Sync`, so it can't be a Bevy resource without a mutex — the very thing this -# bridge deletes). The canonical Bevy background-thread→channel→system idiom. See decision 0006. +# Thread-to-ECS channels such as the net bridge's: crossbeam's `Receiver` is `Sync`, so either end +# can be a Bevy resource without a mutex. crossbeam-channel = "0.5" benilla-assets = { path = "../benilla-assets", default-features = false } benilla-formats = { path = "../benilla-formats", default-features = false } benilla-protocol = { path = "../benilla-protocol" } benilla-world = { path = "../benilla-world", default-features = false } -# The CVar config diff (`benilla/config.toml`, decision 0954): serde derive on the persisted -# shape, toml as its format. (serde_json left with the era manifest — 0978.) +# The CVar diff persisted in `benilla-config/config.toml`. serde = { version = "1", features = ["derive"] } toml = "0.8" -# ECS-native physics: collider storage + broadphase BVH + shape-casts, with a thin custom kinematic -# character controller on top (decision 0009). Pinned 0.6: it targets Bevy 0.18 (verified single, -# unified bevy 0.18.1 in the tree); 0.7.0 jumps to Bevy 0.19 and would duplicate bevy. avian wraps -# parry under the hood, so adopting it lets us drop the *direct* parry3d dep once the bespoke -# CollisionWorld is gone. See docs… (decision 0007 superseded by 0009). +# Collision for our kinematic character controller; 0.6 targets Bevy 0.18, 0.7 moves to 0.19. avian3d = "0.6" -# The glyph shaper + rasterizer for `FontString` text (decision 0068 §2, probe-verified in -# `probes/text-glyph`). Pinned to 0.16 — the exact version already in the tree transitively -# (`bevy_text`'s own dependency, see `Cargo.lock`) — so this is the *same* `cosmic-text` the decision -# already commits to, not a second copy. Used as a standalone shaper/rasterizer (`FontSystem` + -# `Buffer` + `SwashCache`) in `ui_text.rs`, never `bevy_text`'s `Text2d`/ECS integration (that path -# doesn't feed our custom z-ordered `UiQuad` stream). +# Shapes and rasterizes `FontString` text standalone (`ui_text`), at bevy_text's own 0.16. cosmic-text = "0.16" -# The font database `cosmic-text` 0.16 uses (its `Source`/`ID`/`FaceInfo` appear in `ui_text.rs`'s -# public-in-crate types). Pinned to the exact version `cosmic-text` 0.16 depends on so there's one -# `fontdb` in the graph. +# `cosmic-text`'s font database, whose types `ui_text` names; must stay the version it depends on. fontdb = "0.23" -# kira renders the mix; the device it plays through is OURS (`sound::output`, decision 1857) — -# kira's own `cpal` backend is not enabled on any target. On macOS that took cpal out of the graph -# entirely: it could neither report a lost default device nor rebuild on one, and it discarded the -# IO-cycle timestamp the deadline meters need. Off macOS cpal is back (1920) but as OUR device -# layer under the same backend, not as kira's — the ring, the render thread and the meters are the -# same code on every platform. +# The mixer. Its `cpal` backend stays off on every target: `sound::output` is our own backend. kira = { version = "0.12", default-features = false, features = ["mp3", "wav", "pcm", "adpcm"] } -# The realtime-audio allocation tripwire (decision 1857): `assert_no_alloc(|| …)` around the output -# IO callback and the render pass aborts a DEBUG build on any allocation inside them, so a -# realtime-safety regression fails a test or a smoke instead of reaching an ear. Release builds -# compile it out (`disable_release`, the crate's default) and carry no allocator wrapper. +# Aborts a debug build on an allocation in the audio IO callback or render pass; off in release. assert_no_alloc = "1.1" -# kira's own decoder, named directly for one trait: the mixer feeds streams through its own -# `MediaSource` so kira's per-stream decode thread runs OUR code and can promote its QoS (decision -# 1109 — a bare-spawned decode thread starves under the world-entry burst and zero-fills the mix). -# No codecs of its own (kira's features enable those); must stay the version kira resolves — one -# symphonia in the graph, or the trait impl won't line up. +# For `MediaSource`: kira's decode thread reads through our source, which raises the thread's QoS +# so the world-entry burst cannot starve it. Must stay kira's version, or the trait won't match. symphonia = { version = "0.5", default-features = false } -# The mix tap's audio-thread → writer-thread ring (decision 1112): the tap effect must never -# block or allocate on the render path. kira's own SPSC ring crate; kept on the version kira -# resolves so the graph carries one rtrb. +# The audio threads' lock-free SPSC rings (output, mix tap); kira's version, so the graph has one. rtrb = "0.3" mint = "0.5" -# The gossip greeting is a weighted random DRAW per menu-open, not a fixed pick (wow-re -# `gossip-npctext-law.md` — the reference re-rolls in its gossip handler), so the app needs a uniform -# source. Pinned to 0.8: the version `benilla-srp` already depends on, so this adds no crate. +# The gossip greeting's weighted draw, re-rolled per open as in the reference; `benilla-srp`'s 0.8. rand = "0.8" -# Linux/BSD: the Wayland clipboard (decision 0702). We build with bevy's `wayland` feature, so on a -# Wayland session winit gives us a native Wayland window and `arboard` — X11-only without its -# non-default `wayland-data-control` feature — finds no X11 CLIPBOARD owner and every paste fails. -# smithay-clipboard is the right crate for a windowed app: it drives the *standard* `wl_data_device` -# off our own `wl_display`/seat, which every compositor supports. arboard's own Wayland feature would -# not do: it speaks `wlr-data-control`, a privileged manager protocol GNOME/Mutter deliberately -# doesn't implement. `raw-window-handle` (pinned to the 0.6 already in the tree via bevy_window, so -# this adds no crate) is only needed to read the `wl_display` out of bevy's `RawHandleWrapper`. +# Linux/BSD Wayland clipboard: smithay-clipboard drives the standard `wl_data_device` on our own +# `wl_display`, read through raw-window-handle (bevy's 0.6). arboard's Wayland feature speaks +# `wlr-data-control`, which GNOME does not implement. [target.'cfg(all(unix, not(any(target_os = "macos", target_os = "android"))))'.dependencies] raw-window-handle = "0.6" smithay-clipboard = "0.7" -# macOS: drive a native NSCursor for a crisp hardware cursor. winit drives the cursor via AppKit -# cursor-rects, which our continuous Metal render loop doesn't honor on mouse-move (custom cursor / -# hide revert to the arrow); we bypass it with NSCursor + NSWindow::disableCursorRects -# (`video::cursor`). +# macOS: AppKit through objc2 drives a native NSCursor with the window's cursor rects disabled; +# winit's cursor rects revert to the arrow under our continuous render loop (`cursor.rs`). [target.'cfg(target_os = "macos")'.dependencies] -# The audio device layer (decision 1857, `sound::output::coreaudio`): the HAL output unit through -# coreaudio-rs's `AudioUnit`, and the AudioObject property/listener API through the objc2 CoreAudio -# bindings — the two crates cpal itself stood on, now used directly. The versions are the ones the -# graph already carries; the feature sets are the ones cpal proved to compile against. +# The audio device layer (`sound::output::coreaudio`): the HAL output unit through coreaudio-rs, +# the AudioObject property API through objc2-core-audio, at the versions and features cpal uses. coreaudio-rs = { version = "0.13", default-features = false, features = ["audio_unit", "core_audio"] } objc2-core-audio = { version = "0.3", default-features = false, features = ["std", "AudioHardware"] } objc2-core-audio-types = { version = "0.3", default-features = false, features = ["std", "CoreAudioBaseTypes"] } @@ -174,20 +99,12 @@ objc2-app-kit = { version = "0.2", features = [ ] } objc2-foundation = { version = "0.2", features = ["NSArray", "NSData", "NSGeometry"] } -# Everywhere else: the same device layer over cpal (decision 1920, `sound::output::cpal`). 1857 -# owns the mix-ahead ring, the render thread and the meters on every platform; only the last -# hop — find the default device, open a stream on it, hand back one buffer per cycle — is -# platform code, and off macOS that hop is ALSA/PipeWire, WASAPI or the host's own API. cpal is -# the layer that already speaks all of them; on macOS it is still not in the graph, because -# there its defects (a no-op error callback on the default device, a pinned `DefaultOutput` -# unit, the discarded IO-cycle timestamp) are exactly what 1857 went direct to escape. On an -# unsupported target cpal compiles to its Null host, which reports no device — the same silent -# posture the old `stub.rs` had, without a second file to rot. +# Off macOS the device layer's last hop runs over cpal (`sound::output::cpal`). macOS goes direct: +# there cpal cannot report or rebuild on a lost default device and drops the IO-cycle timestamp. +# An unsupported target gets cpal's Null host, which reports no device. [target.'cfg(not(target_os = "macos"))'.dependencies] cpal = "0.17" -# Windows: the journal's and the probes' CPU clocks (decision 2219, `perf::clock`) — -# `GetProcessTimes`, `GetThreadTimes` and `GetSystemTimes`, the twins of the `getrusage`, -# `clock_gettime` and `host_statistics64` arms. The version is one the graph already carries. +# Windows CPU clocks for `perf::clock`: `GetProcessTimes`, `GetThreadTimes`, `GetSystemTimes`. [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_System_Threading"] } diff --git a/crates/benilla-assets/Cargo.toml b/crates/benilla-assets/Cargo.toml index 359e8062..0cd91ff2 100644 --- a/crates/benilla-assets/Cargo.toml +++ b/crates/benilla-assets/Cargo.toml @@ -9,10 +9,8 @@ description = "Bevy AssetSource + AssetLoaders over the WoW 1.12.1 MPQ patch cha workspace = true [features] -# Forwarded dev/player seam (0026 · 1173/1174 · 1175). Default-on. `benilla-formats` must be taken -# with `default-features = false` and its `dev` re-exported here: it is default-on there too, so -# without this a `--no-default-features` player build gets the feature back through unification and -# the binary carries the build machine's source-tree path after all. +# The dev/player seam, on by default. `benilla-formats` comes in without default features and its +# `dev` is forwarded here, or unification would put it back in a player build. default = ["dev"] dev = ["benilla-formats/dev"] @@ -20,7 +18,7 @@ dev = ["benilla-formats/dev"] anyhow.workspace = true bevy.workspace = true benilla-formats = { path = "../benilla-formats", default-features = false } -# Nearest-neighbour resize for off-Elwynn layer BLPs authored below LAYER_TEX_SIZE (texel -# replication in gamma byte space — no averaging, so the C2 mid-tone darkening can't creep in). +# Nearest-neighbour resize of layer BLPs smaller than `LAYER_TEX_SIZE`: texel replication in gamma +# bytes, with no averaging to darken mid-tones. image = { version = "0.25", default-features = false } serde = { version = "1", features = ["derive"] } diff --git a/crates/benilla-blp/Cargo.toml b/crates/benilla-blp/Cargo.toml index c0c84dae..d50a5075 100644 --- a/crates/benilla-blp/Cargo.toml +++ b/crates/benilla-blp/Cargo.toml @@ -10,6 +10,5 @@ workspace = true [dependencies] benilla-bytes = { path = "../benilla-bytes" } -# S3TC/DXT block decompression — the same fixed-point codec wow-blp uses, so DXT output is -# byte-identical. Decompression is a deterministic algorithm (no quantization), unlike encode. +# S3TC/DXT block decompression, a deterministic fixed-point decode. texpresso = "2" diff --git a/crates/benilla-buildstamp/Cargo.toml b/crates/benilla-buildstamp/Cargo.toml index 690ae057..f47b2986 100644 --- a/crates/benilla-buildstamp/Cargo.toml +++ b/crates/benilla-buildstamp/Cargo.toml @@ -9,6 +9,5 @@ description = "The git build-id stamp emitter shared by the launcher shims' buil workspace = true [lib] -# A build-dependency only. No tests, no bevy, no app deps — it runs inside cargo's build-script -# pass and must stay trivially cheap to compile. +# A build-dependency only: it runs in cargo's build-script pass, so it must stay cheap to compile. path = "src/lib.rs" diff --git a/crates/benilla-formats/Cargo.toml b/crates/benilla-formats/Cargo.toml index d018a5ad..e9495141 100644 --- a/crates/benilla-formats/Cargo.toml +++ b/crates/benilla-formats/Cargo.toml @@ -9,12 +9,9 @@ description = "WoW 1.12.1 asset-format adapters (MPQ/BLP/DBC/ADT/WDT) and the be workspace = true [features] -# The dev/player seam (0026, built by 1173/1174). Default-on, so every normal build keeps the -# instruments; `--no-default-features` is the player build. Here it gates exactly one thing: -# `install::candidates`' project-folder probe, which bakes THIS source tree's absolute path -# (decision 1175). EVERY dependent must take this crate with `default-features = false` and -# re-export `dev`, or feature unification puts `/Users/…` back into a player binary — -# `scripts/gates.sh`'s `--no-default-features` line is what catches getting that wrong. +# `dev` gates one thing, `install::candidates`' project-folder probe, which bakes this source +# tree's path into the binary. Every dependent takes this crate without default features and +# forwards `dev`, or unification puts the path back into a player build. default = ["dev"] dev = [] @@ -27,15 +24,7 @@ benilla-dbc = { path = "../benilla-dbc" } benilla-m2 = { path = "../benilla-m2" } benilla-mpq = { path = "../benilla-mpq" } benilla-blp = { path = "../benilla-blp" } -# PNG only, matching every sibling crate. `image`'s DEFAULT features enable `avif`, which drags -# in ravif -> rav1e -> av-scenechange: a complete AV1 video ENCODER, monomorphized into this -# crate, for the two calls below that both write a PNG. Cutting it takes this crate's graph from -# 112 to 48 dependencies and the workspace's from 499 to 466. -# -# It is NOT why `cargo play` used to fail to link -- that was rustc #86049, fixed by `lto = "off"` -# in `[profile.play]` (decision 1698). The tempting story is that rav1e's monomorphized bulk is -# what tripped it; the evidence says otherwise, since 2 of the 7 poisoned codegen units held only -# our own DBC catalog loaders. Two independent wins, and this is the smaller one. Decision 1698. +# PNG only: the default `avif` feature would pull in rav1e, a whole AV1 encoder, to write PNGs. image = { version = "0.25", default-features = false, features = ["png"] } benilla-wdt = { path = "../benilla-wdt" } benilla-wmo = { path = "../benilla-wmo" } diff --git a/crates/benilla-mpq/Cargo.toml b/crates/benilla-mpq/Cargo.toml index 1f9dd5c5..602f549e 100644 --- a/crates/benilla-mpq/Cargo.toml +++ b/crates/benilla-mpq/Cargo.toml @@ -9,11 +9,7 @@ description = "Read-only MPQ archive reader for WoW 1.12.1 (build 5875) — in-r workspace = true [dependencies] -# Bounds-checked byte readers + the allocation-cap guard (decision 0064). MPQ migrates minimally: the -# hand-rolled rd_u16/rd_u32 move to ByteExt and the header/block-table/sector allocations get capped; -# nothing else here changes (this crate is StormLib-pinned and deliberately not churned further). +# Bounds-checked byte readers and the allocation cap on the header, block table and sectors. benilla-bytes = { path = "../benilla-bytes" } -# zlib/inflate for the ZLIB (0x02) sector codec. miniz_oxide backend (pure Rust); no C, no archive -# writing. Any other codec the differential pass turns up in real 1.12.1 data (e.g. PKWARE-DCL 0x08) -# gets vendored alongside; `decompress` errors loudly on an unknown method so nothing is missed. +# Inflate for the ZLIB (0x02) sector codec, on its pure-Rust miniz_oxide backend. flate2 = "1.1" diff --git a/crates/benilla-protocol/Cargo.toml b/crates/benilla-protocol/Cargo.toml index 93046597..7bc71d87 100644 --- a/crates/benilla-protocol/Cargo.toml +++ b/crates/benilla-protocol/Cargo.toml @@ -14,11 +14,10 @@ clap.workspace = true benilla-srp = { path = "../benilla-srp" } flate2 = "1.0" sha1.workspace = true -# `SessionEventKind` — the fieldless twin of `SessionEvent`, the key the app's packet-handler -# table dispatches on (decision 2305). A derive, so the two can never drift apart. +# Derives `SessionEventKind`, `SessionEvent`'s fieldless twin that the handler table keys on. strum = { version = "0.26", features = ["derive"] } [dev-dependencies] -# The SRP probes re-derive the handshake by hand (to vary what `benilla-srp` fixes) — examples only. +# The SRP probe example re-derives the handshake by hand, to vary what `benilla-srp` fixes. num-bigint = "0.4.6" rand = "0.8.6" diff --git a/crates/benilla-ui/Cargo.toml b/crates/benilla-ui/Cargo.toml index 96f2f778..993b44a2 100644 --- a/crates/benilla-ui/Cargo.toml +++ b/crates/benilla-ui/Cargo.toml @@ -10,7 +10,5 @@ workspace = true [dependencies] roxmltree = "0.20" -# The embedded Lua runtime for the script host (decision 0068). `lua51` = Classic Era's Lua -# version; `vendored` builds PUC-Rio Lua from source (no system dependency). 0.11 matches the -# runtime that decision 0068's probe A verified (mlua + the LUAI_MAXCSTACK=8000 finding). +# The script host's Lua 5.1; `vendored` builds it from the workspace's patched `lua-src`. mlua = { version = "0.11", features = ["lua51", "vendored"] } diff --git a/crates/benilla-visual/Cargo.toml b/crates/benilla-visual/Cargo.toml index 266d5ea7..0ddda1db 100644 --- a/crates/benilla-visual/Cargo.toml +++ b/crates/benilla-visual/Cargo.toml @@ -10,6 +10,5 @@ workspace = true [dependencies] anyhow.workspace = true -# PNG-only image IO + the RgbImage buffer the metrics run over. No Bevy — this is the pure-math half of -# the harness, so it compiles fast and runs under `cargo test --workspace`. +# PNG IO and the `RgbImage` buffer the metrics run over; no Bevy, so the crate stays fast to test. image = { version = "0.25", default-features = false, features = ["png"] } diff --git a/crates/benilla-world/Cargo.toml b/crates/benilla-world/Cargo.toml index 22634e54..31b1668d 100644 --- a/crates/benilla-world/Cargo.toml +++ b/crates/benilla-world/Cargo.toml @@ -9,42 +9,31 @@ description = "The world renderer: terrain, water, sky, weather, models, lightin workspace = true [features] -# Forwarded dev/player seam (0026 · 1173/1174 · 1175). Default-on. `benilla-formats` must be taken -# with `default-features = false` and its `dev` re-exported here: it is default-on there too, so -# without this a `--no-default-features` player build gets the feature back through unification and -# the binary carries the build machine's source-tree path after all. +# The dev/player seam, on by default. `benilla-assets` and `-formats` come in without default +# features and their `dev` is forwarded here, or unification would put it back in a player build. default = ["dev"] -# -# `bevy/debug` rides with it (decision 1451): without it every ECS diagnostic — a panicking system, -# a parameter that will not validate, the enforcer's whole fault list — reads ``, which is what the frame-one crash it fixes was reported as. It stores -# `&'static str` names on systems and params; it is diagnostics, not an instrument, so nothing -# depends on it and the player build simply says less. Enabled here rather than in `benilla-app` -# so `benilla-worldview` — the enforcer, whose entire output is these names — carries it too. +# `bevy/debug` names systems and parameters in ECS diagnostics (else "Enable the debug feature to +# see the name"); set here so `benilla-worldview`, which reports those names, gets it too. dev = ["benilla-formats/dev", "benilla-assets/dev", "bevy/debug"] [dependencies] avian3d = "0.6" benilla-assets = { path = "../benilla-assets", default-features = false } benilla-formats = { path = "../benilla-formats", default-features = false } -# The wire crate (`benilla_protocol`) is deliberately NOT here. The engine renders a world; it -# does not speak a protocol. Decision 1177 took the last crossing out — `WorldUnit.kind: -# EntityKind` became `WorldUnit.wades: bool` — and the absence of that dependency line IS the -# record's gate: the crate graph enforces it, so no test has to. -# The WMO group parser — the portal audit re-parses a group to pin its own decode against the file. +# No `benilla-protocol`: the engine renders a world and does not speak the protocol. +# For the portal audit, which re-parses a WMO group to check its decode against the file. benilla-wmo = { path = "../benilla-wmo" } bevy.workspace = true bytemuck = { version = "1", features = ["derive"] } image = { version = "0.25", default-features = false, features = ["png"] } -# macOS: `bgwin` demotes the app to Accessory for a background run and orders the window out of -# the way. Same pins as `benilla-app`'s — one objc2 in the graph. +# macOS AppKit calls, at `benilla-app`'s pins so the graph has one objc2. [target.'cfg(target_os = "macos")'.dependencies] objc2-app-kit = { version = "0.2", features = [ # `bgwin`'s Accessory demotion and window ordering, and `modkeys`' modifier read. "NSApplication", "NSEvent", - # `mac_quit` walks the default menu bar to re-point the Quit item (decision 1528). + # `mac_quit` walks the default menu bar to re-point the Quit item. "NSMenu", "NSMenuItem", "NSResponder", @@ -53,6 +42,5 @@ objc2-app-kit = { version = "0.2", features = [ ] } # `MainThreadMarker`, for the AppKit calls above. objc2-foundation = "0.2" -# `sel!`, for the two selectors `mac_quit` swaps. The pin objc2-app-kit 0.2 itself builds against, -# so this adds a name to the manifest and nothing to the graph. +# `sel!`, for the two selectors `mac_quit` swaps; the objc2 that objc2-app-kit 0.2 builds against. objc2 = "0.5" diff --git a/crates/benilla-worldview/Cargo.toml b/crates/benilla-worldview/Cargo.toml index a7a7d236..b22afe71 100644 --- a/crates/benilla-worldview/Cargo.toml +++ b/crates/benilla-worldview/Cargo.toml @@ -9,8 +9,7 @@ description = "The world viewer: the engine with no game attached — and the wa workspace = true [dependencies] -# **Only the engine.** This is the edge the binary exists to hold: if a world concept -# ever needs the game, this line is what refuses to let it. +# Only the engine, never a game crate: a world concept that needs the game fails to build here. benilla-world = { path = "../benilla-world" } [build-dependencies] @@ -19,6 +18,5 @@ benilla-buildstamp = { path = "../benilla-buildstamp" } [[bin]] name = "benilla-worldview" path = "src/main.rs" -# Same reason as the `benilla` shim: test-building this bin would relink the app in the test -# profile on every sha change, which is the tax the shims exist to kill (decision 0993). +# Test-building this bin would relink it on every commit, since the build stamp changes. test = false diff --git a/crates/benilla/Cargo.toml b/crates/benilla/Cargo.toml index 4505c87c..a627ce09 100644 --- a/crates/benilla/Cargo.toml +++ b/crates/benilla/Cargo.toml @@ -9,20 +9,15 @@ description = "The launcher: build.rs stamps the git build id, main() hands it t workspace = true [features] -# The dev/player seam, forwarded (decisions 0026 + 1173): this shim is the binary a player would -# run, so `cargo build -p benilla --no-default-features` is the player build — and the gate. +# The dev/player seam: `cargo build -p benilla --no-default-features` is the player build. default = ["dev"] dev = ["benilla-app/dev"] -# Forwarded profiling switches, so `cargo run --features tracy -p benilla` keeps working. +# Profiling switches, forwarded so `cargo run -p benilla --features tracy` works. tracy = ["benilla-app/tracy"] trace_chrome = ["benilla-app/trace_chrome"] [dependencies] -# `default-features = false` is LOAD-BEARING, not tidiness: without it `cargo build -p benilla -# --no-default-features` still builds the library with ITS defaults (a path dep gets its own), -# so the player-build gate would compile the full dev tree and pass no matter what. Measured on -# 1174's first green run — `cargo tree` listed bevy_egui either way. The `dev` feature above is -# what turns the instruments back on, and it is on by default here. +# `default-features = false`, or `--no-default-features` here still builds benilla-app with `dev`. benilla-app = { path = "../benilla-app", default-features = false } [build-dependencies] @@ -31,6 +26,5 @@ benilla-buildstamp = { path = "../benilla-buildstamp" } [[bin]] name = "benilla" path = "src/main.rs" -# No tests live here — and test-building this bin would relink the whole app in the test profile -# on every sha change, which is the exact tax the shim exists to kill (decision 0993). +# No tests here, and test-building this bin would relink the whole app on every commit. test = false