a fresh clone gets the whole project, and the maintainer's tooling moves out

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>
This commit is contained in:
Sam
2026-09-23 17:27:14 +07:00
co-authored by Claude Fable 5.1
parent 64dc60f52f
commit aff5203393
106 changed files with 2145 additions and 3254 deletions
+27 -8
View File
@@ -24,7 +24,8 @@ fork, and forks are welcome.
## How a change is judged
1. `scripts/gates.sh` is green: fmt, clippy with warnings denied, the workspace tests, the
player build.
doc-link and render-pass lints, the player build with its own tests, and the engine boot
checks.
2. The reference fact is stated: what 1.12.1 does, and where that is known from (the client's
behaviour you observed, a DBC field, a FrameXML line, a packet capture). The names and shapes
under `reference/` are the surface benilla tracks.
@@ -34,12 +35,30 @@ fork, and forks are welcome.
## Setting up
- A 1.12.1 install of your own: `WOW_DATA=<path>`, or a `WoW` link at the repo root. benilla
reads it and never writes into it.
- A server to test against: any 1.12.1 server. The project runs against a local vmangos
(`WOW_HOST`, `WOW_USER`, `WOW_PASS`).
- `cargo play` builds and runs the play profile. `scripts/check.sh` verifies a round of work;
`scripts/gates.sh` is what a pull request must pass.
- Bugs, questions and ideas go to the Discord linked from the README. Issues are off on purpose.
- **The toolchain.** Stable Rust (`rust-toolchain.toml` adds clippy and rustfmt) and a C
compiler, because the client's Lua is vendored and built from source. On macOS the Xcode
command line tools, which also supply libclang for the audio bindings; on Linux the ALSA and
udev development packages and pkg-config. `python3` runs two of the gates, and `jq` the hooks.
- **A 1.12.1 install of your own.** `WOW_DATA=<its Data folder>`, or a `WoW` link at the repo
root, which only a dev build sees: the player build looks for `Data/` or `WoW/Data/` beside
the binary. benilla reads the install and never writes into it. `WOW_DATA=` (set, empty)
means "no install", which is how the no-install boot is tested on a machine that has one.
- **Without the install, green is hollow.** About a thousand tests read the install and skip
when it is absent; six more read a corpus of vanilla addons (`BENILLA_ADDON_CORPUS=<a folder
of addons>`, or a `wow-addons-vanilla` link at the root), third-party content that is not in
this repo. `scripts/gates.sh` and `scripts/check.sh` print how many tests skipped and why.
Where the data is, `BENILLA_REQUIRE_DATA=1` turns a skip into a failure, and the gates set it
themselves when the install and the corpus both resolve.
- **A server to test against.** Any 1.12.1 server; `WOW_HOST` names it (default
`localhost:3724`). A scripted run has no default account: `WOW_USER`, `WOW_PASS` and
`WOW_CHAR` name a test account on your server whose login kicks nobody, all three, either in
the environment or in a `.probe-identity` file at the repo root (one per line, never
committed), and `scripts/smoke.sh` (the live login gate) refuses without them. The probes
drive the body with GM commands, so give that account the top GM level.
- **The loop.** `cargo play` builds and runs the play profile. `scripts/check.sh` verifies a
round of work; `scripts/gates.sh` is the full chain, and it opens a window for the engine boot
checks, so it needs a display. Work on a branch.
- Bugs, questions and ideas go to the Discord linked from the README. Issues are off on purpose,
and pull requests are not open yet.
Working with an AI agent is expected. The agent reads `AGENTS.md`, and the same rules bind it.
+17 -37
View File
@@ -36,8 +36,8 @@ comment naming the reference fact and why we differ. Anything else is a fork.
- **Never commit anything from the install.** Art, models, sounds, maps, data: the install is
read at runtime from a gitignored path, and everyone provides their own. The one exception is
interface code: FrameXML and GlueXML run off the player's own patch chain, and the copies
already under `assets/ui` stay until they retire.
interface code: FrameXML and GlueXML run off the player's own patch chain, and our own
counterparts under `assets/ui` stay until they retire.
- **The install is read-only.** benilla never writes into the WoW folder: no screenshot, log,
cache or scratch file. A hook blocks such a write at the tool call, and `scripts/smoke.sh`
fails a run that leaves the install changed.
@@ -69,45 +69,31 @@ comment naming the reference fact and why we differ. Anything else is a fork.
## Gates
- **The land gates**: `cargo fmt --all -- --check`, `cargo clippy --workspace --all-targets
-- -D warnings`, `cargo test --workspace`, the player build without the `dev` feature and the
engine boot checks, as `scripts/gates.sh`. `wt.sh land` runs it on the tree that lands; it is
memoized on the tree.
-- -D warnings`, `cargo test --workspace`, the doc-link and render-pass lints, the player
build without the `dev` feature with its own tests, and the engine boot checks, as
`scripts/gates.sh`. It runs on the tree that lands, before it lands; it is memoized on the
tree. The tests that read the install or the addon corpus skip where the data is absent, and
the gate prints the count; where the data is, a skip is a failure (`BENILLA_REQUIRE_DATA=1`).
- **Per round**: `scripts/check.sh`, scoped to the changed crates and their dependents. Run each
gate once per round; `tee` the output to a file and grep the file.
- **A clean run** is the fourth gate: `scripts/smoke.sh`, a live login and logout against the
local server. For wire work the gate is a live run with a trace (`WOW_MOVE_TRACE=<path>`,
tags filtered), never a capture: capture mode has no network.
- **Platform seams**: a `cfg(target_os)`, a `[target.'cfg(…)']` dependency, a `#[link]` or an
`extern "system"` is invisible to the macOS gates. `scripts/crosscheck.sh` compiles Linux and
Windows, and the land worker runs it when the diff touches a seam.
- **Vulkan**: `scripts/vkleg.sh` runs the client on Vulkan in a container before a release,
because Metal cannot ask what Vulkan validation refuses.
- Hooks enforce only two things: no writes into the install, and the worktree rule on a machine
with a pool. Everything else is a gate or discipline.
## Worktrees
On a machine with a pool, every session works in its own slot and `scripts/wt.sh` is the only
way to get one. `claim <name>` at the start; `land <name>` at the end, which rebases,
regenerates the map, runs the full gate chain, fast-forwards and pushes main and releases the
slot, one land at a time; `release` to abandon; `status` to see the pool. Never the primary
checkout, which belongs to no session and stays clean, and never the harness worktree tool or a
hand-rolled `git worktree add`. Work against the slot by path: prefix Bash calls with
`cd <slot> &&` and give edits absolute paths under it. No free slot means stop and ask which
one to take over, never fall back to the primary. Hooks enforce all of this.
Sessions share the machine, so a kill is scoped to a PID, never to a command pattern:
`pkill -f "cargo test"` takes out every neighbour's gates along with yours.
On a plain clone there is no pool: work on a branch and open a pull request.
`extern "system"` is invisible to the gates of the platform you are on. Say in the commit
which platforms you built.
- One hook: no writes into the install. Everything else is a gate or discipline.
## The local server
benilla talks to a local vmangos (build 5875); `WOW_HOST`, `WOW_USER`, `WOW_PASS` and `WOW_CHAR`
override the defaults. These bind every session and every agent:
benilla talks to any 1.12.1 server: `WOW_HOST` names it (default `localhost`), `WOW_USER` and
`WOW_PASS` together log in without typing, `WOW_CHAR` picks the character. There is no default
account. These bind every session and every agent:
- A probe logs in as its own probe account (`probeN` for `pool-N`), never as a player's: a login
kicks whoever holds the account.
- A scripted run logs in as the account its checkout declares in `.probe-identity` (the three
variables, one per line, never committed), or as the three variables name; never as a
player's, because a login kicks whoever holds the account, and the client refuses a scripted
login from a checkout on any account but the declared one.
- Every unattended run says so: `WOW_UNATTENDED=1`. An agent's run is silent: `WOW_NOSOUND=1`.
- No unattended combat probes.
- Anything about hostility, reaction colour, nameplates, threat, damage or breath runs with
@@ -115,9 +101,3 @@ override the defaults. These bind every session and every agent:
- Read the preflight banner before debugging anything else.
The mechanics are the `probe` skill.
## Agents in a shared tree
Parallel agents share one working tree: whole-tree git ops (`stash`, `reset --hard`,
`clean -f`, a pathless `checkout`) are forbidden, diagnostics use path-scoped commands, and an
agent never gets a tree of its own.