benilla is one repo: the working tree moves in, restructured
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>
This commit is contained in:
+123
@@ -0,0 +1,123 @@
|
||||
# METHOD — how benilla is built
|
||||
|
||||
benilla is a from-scratch World of Warcraft 1.12.1 client in Rust and Bevy. It reads the game's
|
||||
data from the player's own install, speaks the original protocol to any 1.12.1 server, and does
|
||||
not build a server or simulate the game. The reference client is the spec: benilla does what
|
||||
1.12.1 does, as a modern, idiomatic client.
|
||||
|
||||
## The rule for every change
|
||||
|
||||
A change is right when it makes benilla more like 1.12.1 or fixes a bug, with evidence from the
|
||||
reference, in one small piece, with the gates green. A deviation from the reference is the
|
||||
maintainer's call alone, and each one is written down where it lives: a CVar's `Deviates` row, a
|
||||
comment naming the reference fact and why we differ. Anything else is a fork.
|
||||
|
||||
## The loop
|
||||
|
||||
1. **The reference first.** For anything fidelity-defining, get the mechanism from the real
|
||||
client before building: its behaviour, a DBC field, a FrameXML line, a packet capture. The
|
||||
names and shapes under `reference/` are the surface benilla tracks.
|
||||
2. **Build it idiomatically.** Modern Bevy and Rust, performance woven in from the start.
|
||||
Implement the mechanism well; do not ape a quirk that is a bug.
|
||||
3. **Measure, never eyeball.** Timing, delay, ordering and feel are settled with instruments:
|
||||
trace timestamps, byte-derived numbers, a numeric probe. A capture confirms an existence
|
||||
fact; it cannot measure time. Never search for a viewpoint: take the one simplest shot, and
|
||||
if it does not settle the question, hand over a precise script ("log in, look at X, does Y?").
|
||||
4. **Close the loop on the symptom.** A bug reported as seen is closed by reproducing it at the
|
||||
reported spot first, fixing, and showing the same instrument clean there plus one adjacent
|
||||
state. Green gates and an existing mechanism are never that evidence.
|
||||
5. **Prove the run before reading the result.** A live result is evidence once the run is valid
|
||||
from numbers: preflight banner clean, camera and body where intended, the subject in frame,
|
||||
the window long enough. A negative from an unproven run is not evidence.
|
||||
6. **Commit small and often.** Atomic units, explicit paths; main only advances by fast-forward.
|
||||
No "done" and no commit without saying what was verified and how the result was judged.
|
||||
|
||||
## Hard rules
|
||||
|
||||
- **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.
|
||||
- **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.
|
||||
- **Local state lives in one folder**, `benilla-config/` beside the binary, and every path to
|
||||
it resolves through `crate::local_state`. Player settings are CVars persisted as a diff in
|
||||
`benilla-config/config.toml`.
|
||||
- **UI is stock-first: a window is migrated, not authored.** The end state is the stock 1.12
|
||||
FrameXML executed off the player's own chain. `assets/ui` does not grow: a test names its
|
||||
files and fails on a new one. A window is built by pointing `benilla.toc` at the stock file,
|
||||
deleting ours and building the engine verbs it calls, never stubbing one to make the file
|
||||
load.
|
||||
- **A setting's default is the reference's default.** Every option boots at the stock 1.12
|
||||
value. Shipping another value costs an explicit `Deviates` row with the reason, and a test
|
||||
fails a row that drifts either way.
|
||||
- **Our code is MIT OR Apache-2.0**, which is a claim about provenance: no original client
|
||||
code, no bundled assets.
|
||||
|
||||
## Where things live
|
||||
|
||||
- `docs/METHOD.md`, this file: rules and method. Never state, never a log.
|
||||
- `docs/MAP.md`: what is built, generated from the code by `scripts/genmap.sh` at every land.
|
||||
Read it to orient; never edit or commit it by hand.
|
||||
- git: the history. No changelogs, no status docs, no "what we did" narratives.
|
||||
- The code: a comment says what the code does and the 1.12 fact behind it, in a line. No
|
||||
history, no stories.
|
||||
- `.claude/skills/`: procedures with steps. `probe` runs the client unattended against the local
|
||||
server.
|
||||
|
||||
## 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.
|
||||
- **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.
|
||||
|
||||
## 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:
|
||||
|
||||
- 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.
|
||||
- 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
|
||||
`WOW_GM=off`.
|
||||
- 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.
|
||||
Reference in New Issue
Block a user