`docs/METHOD.md` asks each deviation to name the reference fact and why benilla differs, and `docs/DEVIATIONS.md` is generated from those comments. The generator wrote only a comment's lead: its first sentence, extended to at least 70 characters. A comment that gives its reason first lost the reference fact from the list, as the Warden entry did after its reason was restored.
The list now writes each comment's whole paragraph, the one the reason check already reads. The lead and sentence helpers are gone with it.
Tested by regenerating the list: every entry keeps its full paragraph, and the Warden entry shows the reference's handling of `SMSG_WARDEN_DATA` again.
Fixes#2880🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`docs/METHOD.md` asks each deviation to name the reference fact and why benilla differs. About 130 `Deviation:` comments gave no reason, and the Warden comment lost its reason when the refusal became a read-past.
- `scripts/genmap.sh --check`, now a gate, fails a `Deviation:` comment without "because" and a `Deviates` row without a Why.
- `scripts/deviation-why.allow` lists the 43 comments whose change recorded no reason. It only shrinks: an entry that gains its reason, or is new against main's copy, fails.
- About 190 comments that gave their reason in other words now say "because", with their meaning kept.
- Nine reasons, the Warden one among them, come back from the commits and pull requests that made them.
Tested by the gate on the full tree, and by its failure on a comment with no reason and on a stale entry.
Fixes#2856Fixes#2857🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`scripts/smoke.sh` and `scripts/summon-live.sh` run under `set -o pipefail` and checked their log markers as `printf '%s' "$log" | grep -q marker`. `grep -q` exits at its first match, so on a long log `printf` died of SIGPIPE, the pipeline returned 141, and a clean run failed: "no roster came on the same link after the logout", with the line right there in the log. Replaying the check on one 73 KB run log failed 15 times in 50.
Each check now reads a here-string (`grep -q marker <<<"$log"`), which no early exit can break. The same replay passes 200 of 200, and a missing marker still fails the check.
Fixes#2733
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A full `benilla-app --lib` run cost about 1,050 CPU-seconds, most of it building a headless client per test, and `check.sh` ran the scoped suite twice.
- `order_the_pass` sums each system's access with the host's in one reused buffer instead of cloning the host's access per system; `PassOrder` is unchanged.
- Fixtures that never run the app use `headless_client_unrun()`: every plugin and schedule but `Main` and `Update`, so the pass is never ordered. Running the app or reading the pass from it panics.
- The headless client skips the tonemapping tables, and the handler and lane access lists are measured only when a test asks.
- `check.sh` runs each scoped suite once (`test-no-install` stays in the gates) and adds the player build's schedule tests when `benilla-app` changes.
Measured: 602 CPU-seconds for the same run, 43% less.
Fixes#2324Fixes#2325🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`scripts/check.sh` ran the scoped tests with the install only, so a test that reads the install without `wow_data_or_skip!` passed every round and failed first in the gates' `test-no-install` leg, at the land.
`check.sh` now runs that leg on its own scope, right after its tests: `WOW_DATA=` set and empty, `BENILLA_REQUIRE_DATA` unset, the same `scripts/unit-tests.sh` and package flags. It builds nothing new, so it reuses the binaries the test step just built; on the three app and UI crates it ran 8434 tests in under a minute.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The test gates ran `cargo test`, which runs the workspace's test binaries one after another. On a warm tree the workspace's tests take 103 s that way, and 59 s under cargo-nextest, which runs every binary's tests in one pool; all 10,411 pass both ways.
`check.sh` and `gates.sh` now run tests through `scripts/unit-tests.sh`: cargo-nextest where it is installed, else `cargo test` as before. nextest runs no doctests, so `scripts/doc-tests.sh` runs those of the library crates in scope. Each gate keeps its environment (`BENILLA_REQUIRE_DATA`, `WOW_DATA=`, the skip log), and a failing run's summary now catches nextest's `FAIL` lines. CI is unchanged.
Test: this land's own gates run under it.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The script host now runs on benilla-lua alone. The vendored C Lua 5.1.5 (`third_party/lua-src`) and mlua are removed, about 17k lines. `vm_parity` checks benilla-lua against the answers the C build recorded on Linux and macOS, and `front_end` checks every corpus chunk's compiled shape against the C build's digest. `GRAMMAR.md` records each grammar change from 5.1, by client address.
A handler's `this`, `event` and `arg1`… are bound in one VM call. An event fire saves and restores `event`, while the handler runner saves only `this` (`0x704d50`).
Ours on the branch: VM fixes from review (hook dispatch counts, registers and frames around a collection, protected-call handlers, library errors) and `vm_parity`'s two-VM leftovers removed.
Tests: the full gate chain on the merged tree, `vm_parity` and `front_end` among them. Live: smoke and a stock-glue login. Load time is level with C Lua, and memory is within 7%.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Sam <samuv.eth@gmail.com>
No gate built the shipped player graph outside tests. The player-tests gate compiles with `cfg(test)`, and clippy ran only on the dev feature set, so the player build's own warnings landed unseen: four unused re-exports that only dev probes used.
A new `player-clippy` gate runs `cargo clippy -p benilla -p benilla-app --no-default-features -- -D warnings` in `scripts/gates.sh`, in CI, and in `scripts/check.sh` when it reaches those crates. `docs/METHOD.md` names it.
The four re-exports are deleted: `ground_derived`, `GroundClamped`, `BodyPartsDesc` and `ATTACH_SLOT_NAMES`. Their dev users import them from the defining modules, with no `allow` left.
Test: an unused import added to `net.rs` fails the new gate.
Fixes#1465🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The stock 1.12 GlueXML screens are now the default in every build: login, realm list, character select and create. benilla's native screens run only in a dev build with `WOW_GLUE_NATIVE=1`, or under the rig and capture runs, which still drive them, until the native screens are deleted. `WOW_GLUE_STOCK` is gone.
On the way:
- An unattended reconnect re-dials the kept realm and lists the roster. Under the stock screens it stalled at the realm list.
- `WOW_CHARSELECT_PICK` selects on the stock screen.
- `smoke.sh` counts the stock run's VMs and fonts.
The stock screens fix the native screens' defects listed below.
Tests cover the switch, the pick and the reconnect. Live: smoke, a kick and re-entry, the player build's boot.
Part of #856.
Fixes#849Fixes#850Fixes#834Fixes#812Fixes#360Fixes#463Fixes#79Fixes#977🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
benilla-lua is a Lua 5.1.5 interpreter in Rust that speaks the 1.12.1 client's grammar. It is opt-in behind the `benilla-vm` feature, with `benilla-mlua`, the slice of mlua that benilla-ui uses, over it. The C build stays the default. Its front end ports 5.1.5's `lparser.c` and `lcode.c`, so registers, limits and messages match the C build's.
Our finish on top:
- the collector counts growth as C does, off the write path;
- frames under a leaky generic `for` start nil, as `luaD_precall`;
- the budget hook counts what C dispatches, and costs nothing when unset;
- `__index` chains stop at 100;
- mlua 0.11's conversions;
- `vm_parity` answers recorded per platform.
Tests: `vm_parity` on both VMs; the front-end corpus (8,543 chunks) against `string.dump`; 7,613 app and UI tests on benilla-lua. Built on macOS; Linux by CI.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Sam <samuv.eth@gmail.com>
With `WOW_GLUE_STOCK=1`, character select, realm list, create and the glue strings still ran native systems. They spawned hidden trees and could write the hidden `GlueDialog`. A refused scripted login showed nothing on the stock screens.
Every native glue system is now gated on `native_glue`. The cross-switch instruments (round trip, login shot, realm smoke) move into `glue_session`. Under stock, `WOW_CHAR` enters by the stock Enter World. The account guard's refusal opens the stock `OKAY` dialog, the path `CGlueMgr::Login` takes for an empty account (`0x46b090`). The schedule's ambiguity ceilings drop to 3939 and 372.
Test: a census fails on any system that touches the native screens' components or resources without the gate; it lists 44 on main. Live: native smoke, a stock login to create and back, a stock logout round trip, the stock realm smoke, and a guard refusal.
Part of #856.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`docs/DEVIATIONS.md` lists every place benilla deliberately differs from 1.12.1, generated by `scripts/genmap.sh` at every land beside `docs/MAP.md`:
- The settings that ship off the reference default, with each one's reason, from the `Deviates` rows.
- Each `Deviation:` comment's first sentence, linked to where it lives, grouped by crate and module.
A test fails if a `Deviates` row takes a shape the generator would misread. README, METHOD and CONTRIBUTING link the doc.
Fixes#1289🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The gates memo kept its verdict for a change under `docs/` or in a top-level `*.md` only, so a change to an issue or PR template ran the whole chain again. No gate reads the templates; the workflows under `.github/workflows` stay code.
Scripts only.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A fresh-clone walk-through as a new contributor found four gaps in the docs:
- No quick test loop: `scripts/check.sh` has nothing to check on a clean clone, and `cargo test -p <crate>` was not mentioned. "The loop" now says both.
- The doc-link lint is a full `cargo doc` of the workspace; METHOD and the script's header now say so.
- What to cite while a benilla-re gap is still open: the client address, with the benilla-re issue or pull request linked.
- When `reference/PIN` moves: only with a change that needs a newer benilla-re row, to a commit on its main. Stated in CONTRIBUTING and `reference/README.md`.
Docs only.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`reference/` held benilla's own copies of the reference's tables, some derived by its own scripts from older inputs: the fire-site table kept one event id where a site fires two, and credited glue-screen sites to in-game events.
Now `reference/` is benilla-re's tables at the commit `reference/PIN` names, byte for byte: bindings, events, glue events, messages, event arguments, verb events, the glue surface, the Lua globals, chat types and groups, and CVars. `scripts/sync-reference.py` copies them, and its `--check` runs in the gates and in CI. Four generators and nine old files go, and every reader moves to the new columns.
New tests hold the chat type, chat group and CVar tables to the copies; the CVar rows already filed are listed as known.
Fixes#245Fixes#960
Part of #244🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A failing test gate printed only its log's last 30 lines. Those are the doc-test runs after the failure, so the failing test's name and its panic were missing from both the gate output and the land log.
scripts/gates.sh and scripts/check.sh now print the panic lines, each test's FAILED line and any compiler errors from the log first, then the tail as before.
Checked on a sample failing log; both scripts pass `bash -n`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Verb events fired from app feeds a frame late; 1.12.1 signals inside the call.
Now each verb raises its events in place. Feeds push only what their own server source changed, so a verb's write is never rolled back.
Also, from the bytes:
- The score board waits on pending names (0x4aa216).
- The recruitment cascade runs inside its verb.
- Seven mail verbs share the request lock 0xb6efc8; the mailbox keeps its inbox across a close.
- StartAuction runs its gates, sends the attached guid and empties the slot in the call.
- The tradeskill repeat counts, disarms and resets as 0x4fd7b0 and 0x4fc750 do.
- Quest folds carry across a /reload.
Tests cover each event's timing and the feed rule.
Fixes#1008Fixes#1009Fixes#1010Fixes#1045Fixes#1046Fixes#1047Fixes#1050Fixes#1051Fixes#1059🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In 1.12.1, logging out or a refused character login returns to character select on the same world connection and re-lists there (`0x5aaeb0` → `0x401ee0`, then `0x46b880` → `CMSG_CHAR_ENUM`). There's no realmd logon and no new `CMSG_AUTH_SESSION`. Enter World closes the realmd link (`0x46b70c` → `0x5b3320`), and only the glue's own re-dials reopen it.
- benilla used to drop the socket and log on again from cached credentials. Now the world session splits and rejoins on one connection, and the header cipher carries its state across.
- The realmd link closes at the pick.
- A leftover packet at character select is skipped rather than fatal.
- The write thread applies a pending writer swap before any command.
- A kept-link teardown ends the character without a "server down".
Fake-server tests pin one logon, one auth and one more enumerate. The logout smoke fails without a same-link relist.
Fixes#984Fixes#983🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The first piece of running the stock GlueXML: benilla had no glue Lua state, and no reference data for its surface.
In 1.12.1 the glue state holds the base set (`0x7039e0`) and seven registrars (`0x46abb0`): 119 functions, 105 of them glue-only, with 26 glue events (`0xb41e70`, `0x46a88f`). `RegisterEvent` matches names case-insensitively and drops an unknown one (`0x702140`). The glue builds the 13 base frame types plus `ModelFFX` (`0x46a4fe`), a Model with its own show and paint (`0x46fa00`); the in-game types come only at world entry (`0x495940`).
`reference/` gains the glue event and surface tables, generated and checked against the shapes table. `UiScript::new_glue()` builds that state; a gate holds its globals to the table, with the 108 unbuilt names listed. Nothing in the app changes yet.
Part of #856🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`cargo test` stops at the first test binary that fails, so a red `scripts/check.sh` or gate run showed one crate's failures and hid the rest: the next run found more. Both scripts now pass `--no-fail-fast`, so one run reports every failing test across the workspace. The exit status is unchanged: any failure still fails the step.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The land chain compiled the player build twice: `cargo build -p benilla --no-default-features`,
then `cargo test -p benilla-formats -p benilla-app --no-default-features --lib`. The test build
already compiles every line of the no-`dev` graph but the `benilla` launcher, a 17-line shim with
no `dev` seam, and `benilla-app` has no `cfg(not(test))` code, so the first step added only the
shim and a link: about two of a chain's twelve minutes. It goes from `gates.sh` and CI, and
`player-tests` carries its comment.
`check.sh` no longer says a full chain before land makes the land free: main moves in between, so
the chain ran twice.
Test: this land's own chain runs the new `gates.sh`.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The core now loads the chain's `Interface\FrameXML\Bindings.xml` after the `FrameXML.toc` rows, as the reference's UI load does. The load checks the file at `0x48fff9` and loads it through the addons' loader `0x4b6f70` at `0x490018`. The default keys come from the chain's `WTF\DefaultBindings.wtf` (`0x4b62b0`). Every command now runs the stock file's own body, and the registry compiled into benilla, with its 91 retyped bodies, is deleted.
- **The loader's rules (`0x4b6f70`).** It reads the root's children only and skips empty, `debug="true"` and non-Windows rows. A second definition of a name is skipped, and duplicate headers are refused.
- **Keys and commands are separate tables, as in 1.12.** `SetBinding` never reads the command (`0x4b7490`). `RunBinding` runs the body in the VM. `RunCommand` sets `keystate` around the body and clears it after (`0x4b7c42`).
- **Engine behaviour sits behind the Lua globals the bodies call.** These are the movement, turn and mouse-steer bits. Focus loss clears the direction bits and keeps the mouse pair (`0x514490`). One key's stop clears its bit, as `0x514b70` does, so releasing W while UP is held stops the character.
- **Behaviour changes that follow the stock bodies.**
- The nameplate keys (V, Shift-V, Ctrl-V) now run the stock bodies.
- ALT-Z runs `CloseAllWindows(); UIParent:Hide()`.
- The minimap, sound, stance and bonus-bar keys call their stock functions.
- The wheel zooms one `CameraZoomIn(1.0)` per notch.
- **Platform.** benilla answers as the PC build, so a `platform="mac"` row does not register on any OS.
Verified:
- New tests: a fixture `Bindings.xml` (reordered, edited, and with debug, empty, nested and Mac rows) drives the command list, defaults and bodies. The V keys follow the stock bodies. No stock body's text remains in the tree. Every stock body's calls resolve after a production load. Each test fails with its change undone.
- `scripts/gates.sh` and `scripts/smoke.sh` are green.
- A live run with `WOW_GM=off`:
- W and Space moved and jumped.
- B toggled the backpack.
- 1 reached `UseAction`.
- V, Shift-V and Ctrl-V behaved as the stock bodies do.
Built on macOS; no platform seam touched.
Fixes#570Fixes#563🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The host's state leaves `_G`: the eleven `__benilla_*` globals, which any addon could read and overwrite, move into the host's model (and, for the error handler, the Lua registry, as the reference keeps it), and the getters over them are Rust bindings answering the reference's shapes.
- `GetTime` returns one number (`0x515ea0`), and `GetGameTime` returns hour then minute (`0x515ee0`). The tick advances the model clock, and every cooldown and buff reader reads it.
- `GetZoneText`, `GetRealZoneText`, `GetSubZoneText` and `GetMinimapZoneText` always answer a string, `""` when unset (`0x48a0a0`-`0x48a100`). `GetZonePVPInfo` answers three values (`0x48d540`).
- `seterrorhandler`/`geterrorhandler` work over a registry slot that starts empty, as the reference's does (`0x7039e0`, `0x702950`, `0x702900`). A non-function raises `Usage: seterrorhandler(errfunc)`. The engine dispatches caught errors through the slot, not through the global (`0x703b40`). The stock `BasicControls.xml` installs `_ERRORMESSAGE` before any addon, so play is unchanged.
- The engine's surface allowlist now holds only `_G`. `scripts/api-coverage.sh` no longer excuses `__` names.
Verified:
- New tests show each of the eleven names absent from `_G` and that writing it changes nothing. On main, `__benilla_now = 0` rewound `GetTime` and every buff and cooldown.
- The getter shapes and the error-handler slot are pinned. The surface gate fails when a name is re-added.
- `scripts/gates.sh` and `scripts/smoke.sh` are green.
- A live run read the clock, zone texts, PvP info and game time, then showed that writing the old names changes nothing.
Built on macOS; no platform seam touched.
Fixes#576🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The core now loads the player's own `Interface\FrameXML\FrameXML.toc` off their chain, row by row in its order (`0x6edb90`, from `UI_Init` at `0x48ffed`), instead of benilla's copy of the list, and `benilla.toc` is gone. Order is observable in 1.12.1: event listeners run in registration order, children are kept in creation order, and hit-test ties go to the earlier frame.
- The world VM starts bare: `GlobalStrings.lua` and `Fonts.xml` load as the toc's first rows. The boot VM keeps `GlobalStrings.lua` and the emote tokens, and no longer loads `Fonts.xml`, which nothing reads there (#307).
- A chain without `FrameXML.toc` builds no stock UI and still loads the layer and addons, as the reference does (`"Couldn't open %s"`, severity 2, return unread); benilla reports it as an error.
- Every test kit now loads in the production order, `FrameXML.toc`'s rows then `layer.toc`'s, and a guard fails any kit that loads out of it. Two tests whose premises the stock order disproves are gone.
- `scripts/smoke.sh` counts VMs by the VM marker, since `Fonts.xml` now loads once per world VM.
Verified: new tests for the load list against the chain toc and a reordered fixture toc, the missing-toc case, and two stock frames on one event running in the toc's order (ExhaustionTick before PlayerFrame on `PLAYER_UPDATE_RESTING`), each failing on main's order. A before/after dump of globals, frames, draw order, event listeners and saved variables differs only in stock-order effects: the reordered listeners and children, draw-order ties between non-overlapping frames, and `UnitPopup`'s quality colours now sharing the live tables. `scripts/gates.sh` and `scripts/smoke.sh` are green, and live before/after runs show 0 errors and identical warnings. Built on macOS; no platform seam touched.
Fixes#555Fixes#307🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
benilla's own interface now loads as one layer on top of the stock UI, as `docs/METHOD.md` now states: the core loads the stock FrameXML rows, the layer (`assets/ui/layer.toc`) loads after the last of them and before the third-party addons, and like FrameXML it has no AddOn API row and fires no `ADDON_LOADED` (the reference loads `FrameXML.toc` outside `AddOn_Load`, `UI_Init` `0x48fbf0`).
- Moved into the layer unchanged: `ScrollTemplates.xml`, `KeyBindingsPage.xml`, `OptionsFrame.xml`, `ContainerFrameAdapters.xml`, `SpellBookAdapters.xml`, `ScriptLogFrame.xml`. `GameMenuFrame.xml` stays the core's last row until #553.
- The host's Lua fixes to stock code (`FCF_ChatTabFadeFinished`, the `DurabilityFrame` re-seat) move into the layer's `FrameXMLFixes.xml`; the resize re-seat stays host-side as an engine adaptation.
- The core now loads `StatsFrame.xml` and runs `LocaleProperties.lua` once, from `UIParent.xml`, so its chain rows are exactly the stock `FrameXML.toc` rows but the menu; the order is #555.
- A dev build boots without the layer under `WOW_STOCK_UI=1`; the host's calls into the layer are guarded.
Verified: new tests for the layer's file list, the core list against the stock toc, the load position (a `_G` definition log), absence from the AddOn API and the stock-only boot, each failing with the change undone; a before/after dump of every global, frame, draw order and saved variable differs only by `StatsFrame` and the moved fixes' source; `scripts/gates.sh` and `scripts/smoke.sh` green, and a live logout/re-login under `WOW_STOCK_UI=1` clean. Built on macOS; no platform seam touched.
Part of #552Fixes#542Fixes#543🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The `player-tests` gate now runs its 30 addon-corpus tests where the corpus is: it passes the `wow-addons-vanilla` link as `$BENILLA_ADDON_CORPUS`, the only way a build without `dev` finds the corpus, and sets `BENILLA_REQUIRE_DATA=1` under the same condition as `test`, so a skip there fails the gate as `docs/METHOD.md` asks. All 30 pass in the player configuration; CI, which has no corpus, is unchanged.
Fixes#453
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The gates of scripts/gates.sh that need neither the install nor a display (fmt, clippy, the
workspace tests without an install, the doc-link and render-pass lints, the player build and its
tests), on ubuntu-latest, so a red pull request is seen before anyone builds it. A branch of this
repository skips the job: it runs the full chain before it lands. The job reads the repository
only, keeps no credentials in the checkout, pins its two actions by commit, drops debuginfo for
the runner's disk and caches dependencies. gates.sh and CONTRIBUTING say what runs where.
actionlint passes; the system packages are the ones CONTRIBUTING names for Linux. The workflow's
first run is a manual one on main once it lands.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The comment and string passes' last leftovers, and one lookup made to match the reference.
**Comments that stated a wrong reference fact**, now stating the right one:
- A cast failure clears the GCD, and a failed cooldown-on-event spell also drops its parked record (`0x6e73cc`).
- `SetUnit` is `0x505d70`; `0x476cb0` is the component clone it reaches.
- Interior sound follows the character, where the listener sits, not the camera.
- Template inheritance re-runs `LoadXML` on the one object against each template (`0x76985c`), and reads `name` and `id` from the instance alone (`0x769770`).
- On the ghost-to-alive edge the reference clears its corpse cache and sends nothing (`0x5ee990`, `0x491f50`).
- The name cache has no high-bit miss. An empty-name answer evicts the record in the reference (`0x55f6f0`).
- The combat-log deferred queue (`0xc4e208`) waits only on an item name. A unit name never waits.
- A flying spline's segments are paced by curve length (`0x454320`, `0x453760`), not by chord length.
- A stop within 3 yd of its stop point keeps the arrow nocked (`0x6019e4`).
- A missile's sound id is at `CMissile+0x40`.
- A nil or unresolved `AssistUnit` token is a gap against `0xb8` ERR_GENERIC_NO_TARGET, not a deviation.
**Strings:**
- Test, log and tool messages lose leftover history wording and placeholder labels.
- The extractor's scan summaries describe the current tint and sequence-clock paths.
- The smoke script's failure text carries no private numbers.
**Line continuations:** twelve log, panic and assert strings get back the `\` continuations they had lost. Each printed a run of spaces mid-message. Fixes#106.
**One lookup:** a region's `inherits=` is looked up as one verbatim name, matched case-insensitively (`0x6ee6f0`, `_strnicmp` at `0x6ee747`), as `framexml::expand` already did for frames. The gate before it split on commas and matched case-sensitively, so a texture or font string whose `inherits=` spelled its template in another case never received the template. `a_region_takes_a_mis_cased_template` fails before this change and passes after.
**Tests:** the quest tests stop loading three FrameXML files that no quest file uses.
**In game:** nothing changes for the stock UI. Log lines read as one sentence, and an addon texture that names its template in another case now gets it.
Verified with `scripts/check.sh` on the changed crates, plus the loader and quest tests with the install present.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Two small fixes.
- `OptionsFrame.xml`: the comment on the missing Use UI Scale checkbox said benilla has no `useUiScale`. It is registered at "0" and never read, which is why the UI scale always applies.
- `scripts/doc-links.py`: `--help` and `-h` print the usage in the module doc instead of running the full `cargo doc` pass.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Comments that pointed into the maintainer's private reverse-engineering notes (a note by name, a
path, a section or finding id, the analysis's own name for a client function, a process word) now
carry the fact itself, cited by the reference client's address, by vmangos file and line, or as
"the reference". Nobody outside could follow those pointers.
Comment text only, plus the test-assert and log strings that carried the same pointers. No claim
changes: a comment the notes have since corrected keeps its wording here, and correcting it is
separate work.
The two reference generators, `scripts/gen-reference-globals.py` and
`scripts/gen-reference-verb-events.py`, named the private notes' layout to find their inputs. They
now take the input files as arguments (`--capture`, `--framexml`, `--names`, `--extents`,
`--disasm`). Run on the same inputs, both write the committed tables row for row; only the two
header lines that named the old environment variable change.
Checked per file:
- the code is identical: each file with its comments stripped compares equal before and after; a
changed string literal is compared under a mask that proves only literal text moved and every
literal kept its line count;
- no client address the old text cited was dropped;
- a second reviewer checked every added address against its derivation;
- a detector for the notes' names, paths, ids, function names and process words finds none left;
- `scripts/gates.sh` is green.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There is no top-level assets/ directory: assets/ui lives under
crates/benilla-app/, which the crates arm already scopes to benilla-app.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The test gate refuses skips only where both the install and the
wow-addons-vanilla link are present. The link is gitignored, so the
tree hash cannot see it, and the stamp kept only the install path. A
green earned without the corpus was therefore reused after the link
appeared, and skips were never refused on that tree. The corpus's
presence now sits beside the install in the stamp. The memo message
also names docs/ as well as top-level *.md.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Each rung keeps one or two lines: what it refuses and the fact that
makes it necessary. The stories of how each gate came to exist are
gone. 148 comment lines become 48; the code is unchanged.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A failure message pointed at records and bug ids that are not in this
repo; each now says the fact alone. Only message text changes.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Docstrings keep their usage and exit codes; table headers keep the
column contract and the client addresses and lose the dates, the
correction history and every path into another repository. A
generated header changes in its generator's template, so each of the
four generators still reproduces its output byte for byte, and no data
row changed in any of the seven tables.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
With no `.probe-identity`, the scrub kept the shell's WOW_USER, WOW_PASS
and WOW_CHAR in the environment, so the realm leg inherited WOW_CHAR and
`realm_select::smoke` refused it: the documented
`WOW_USER=… WOW_PASS=… WOW_CHAR=… scripts/smoke.sh` could never pass.
The account is resolved into the script's own variables first and each
leg passes it by name, so it now leaves the environment either way.
Verified: the scrub run alone with the account in the shell leaves only
WOW_HOST in a child's environment, with and without a declared identity.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Each header is a one-line summary, the environment it reads and its
usage; the history, measurements and record numbers go. Only comment
lines change: with comments stripped the scripts are byte-identical.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
465 tests loaded the stock interface off the install without declaring
it, and 25 addon tests assumed the install beside the corpus; each now
opens with `wow_data_or_skip!`. The gates run the workspace tests a
second time with `WOW_DATA=`, so a test that reads the install
undeclared fails at land instead of on a contributor's clone. The skip
log writes each line in one call so parallel tests do not interleave.
Verified: the workspace tests with `WOW_DATA=` in a checkout that has
the addon corpus pass 6972, fail 0, and log 1555 skips; on a fresh
clone of main before this change they failed 465.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
What a clone lacked: the gates went green with a thousand skipped tests and said nothing, every
login script assumed a worktree-pool slot and its probe account, the client defaulted to the
maintainer's account, a docker path and a home directory were in the code, the temp files broke
on GNU coreutils, and two generators could only run against a sibling repo.
Now the test gates print how many data-gated tests skipped and why; a scripted run logs in as
the account its checkout declares in `.probe-identity` or as the three variables name, never a
default, and the client refuses a scripted login on any other account; the event and message
tables regenerate from vendored inputs, byte for byte; the docs state the real prerequisites.
Out of the tree, into the maintainer's own tooling: the worktree pool, its hooks, the perf leg
runner, the cross-platform compile and the Vulkan container leg — a way of working, and setups
not every machine has. One hook stays: no writes into the install.
Two tests that could never run are gone with their subject: the quest-timer geometry diff
compared a copy of the window that no longer exists (and joined a chain path onto a folder, so
it always skipped), and the FrameXML flag gate now reads the stock files off the player's own
patch chain instead of an extracted folder only one machine had.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Until now this repo was an export of a private tree, pushed as squashed snapshots. From here on
it is the working tree itself, and the private repo is archived.
The root holds AGENTS.md and the Rust and GitHub files only. Everything an agent needs to orient
is in docs/: METHOD.md (the rules and how the project is built, 123 lines, project method only),
MAP.md (generated from the code at every land) and CONTRIBUTING.md (what gets in and how a
change is judged). One skill, `probe`, holds the procedure for running the client unattended
against the local server.
Brought over because the project needs it: reference/ (the 1.12 name catalogues 34 source
files read; the export failed its own tests without them), the gate chain and the pool
(scripts/), the hooks that enforce the install rule and the worktree rule, the full .gitignore,
the `cargo play` alias, and the original wording of eleven source files the export had reworded.
Left out: the decision records (archived with the private repo), the export tooling, the
operator's Discord and triage loop, the lab-laptop scripts and the instruments nothing
references, which live outside the repo now. What read the records is gone from the tooling:
no corpus lint, no records index, no `reserve` verb, no number-collision check.
Three hooks are gone: fmt-at-commit and the file-size nudge were redundant with the gates, and
the assets/ui guard is now a test (`assets_ui_does_not_grow`) that fails for everyone, not only
for a Claude Code session. The remaining pool hooks stand down on a machine without a pool.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>