The quest log never showed the `[n]` count of party members on a quest, because `IsUnitOnQuest` was a stub that always answered nil.
1.12.1 (`0x4dfe10`) checks both arguments first. It reads the row's quest id (`0x4df150`; a header or out-of-range row answers nil before the unit is resolved), resolves the token, and admits only you or one of the four party slots, by guid (`0x4e7f70`). It then needs the unit held as a player and scans the 20 `PLAYER_QUEST_LOG` ids for that quest. The answer is 1 or nil. The ids reach party members on the wire. `UNIT_QUEST_LOG_CHANGED` (`0x51bc63` → `0x51bd90`) fires once whenever any slot of a unit's window changes, so an open log recounts.
Unit snapshots now carry the window, the binding follows those steps, and the event fires. Tests cover each path and run the stock `QuestLogFrame.xml` to a `[2]` row; they fail against the stub.
Fixes#818
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The meeting-stone status query (`CMSG 0x296`) and its text reset ran once per UI VM, and the text drop only on leaving the world. So after a cross-map worldport benilla kept the old text and never asked again.
In 1.12.1 the world-enter cascade's meeting-stone init (`0x490a14` → `0x4c9f40`) resets the text to `UNKNOWN` and sends `0x296`, right after the battlefield init, on every pass: login, every cross-map worldport and every `/reload`. The leave-world sweep `0x490a80` drops the text (`0x490b2f` → `0x4c9f80`) on a worldport, a `/reload` and leaving the world.
The enter leg now runs on the world-enter cascade after the battlefield status. The sweep is one edge, written whenever its latch is spent, and the drop reads it. Tests cover the cascade, a worldport, a reload and the schedule order; a live trace shows `0x296` after `0x2D3` and its reply at login, on `ReloadUI()` and after `.tele`.
Fixes#99
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The `out` trace tag logged only what the long-lived writer sent, drained after each command. Everything the session sends before the reader and writer split never reached it: `CMSG_AUTH_SESSION`, `CMSG_CHAR_ENUM`, `CMSG_PLAYER_LOGIN`, character create and delete, the cinematic ack and logout. So a login trace could not show where `CMSG_PLAYER_LOGIN` sits against `SMSG_LOGIN_VERIFY_WORLD`, which wire-timing work needs.
The world socket has one write path, `send_packet`. It now reports each packet to an observer right after the write, and the app installs the trace there only when the `out` tag is on. The writer's sent-log and its drains are gone; the line format is unchanged.
A protocol test over the fake server checks that the handshake, a pre-split send and a writer send are all observed, in order. A live login trace now opens with `CMSG_AUTH_SESSION`, `CMSG_CHAR_ENUM` and `CMSG_PLAYER_LOGIN`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
At login benilla sent `CMSG_SET_ACTIVE_MOVER`, `CMSG_QUERY_TIME`, `MSG_QUERY_NEXT_MAIL_TIME` and `CMSG_BATTLEFIELD_STATUS` right after `CMSG_PLAYER_LOGIN`, before the server had seated the player. cmangos drops them; after a worldport or `/reload` the time and mail queries never went again.
In 1.12.1 all four follow the local player's own create (`0x5dea50`): `SetActiveMover` (`0x6006e0`), then the world-enter cascade (`0x5deb60 call 0x4908c0`), whose inits send `0x1CE`, `0x284` and `0x2D3` in that order. A cross-map worldport re-creates the player and takes the same route; `/reload` re-enters the cascade alone (`0x490168`).
The four now ride the self create, in that order, and `/reload` re-sends the three. Tests cover login, the create, a worldport, the schedule order and the reload; a live trace shows the order at login, after `.tele` and on `ReloadUI()`.
Fixes#789Fixes#100
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Elias Miettinen <eliaspmiettinen@gmail.com>
Co-Authored-By: Sam <samuv.eth@gmail.com>
- Change `LevelUpInfo` to signed to match vanilla behavior
- Add parse test for negative values in SMSG_LEVELUP_INFO, update comments
- grammar
- level-up gains: cite the %d fire and vmangos's wrapped deltas; pin the reported line
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Sam <samuv.eth@gmail.com>
Percentage costs took their share of the max pool, so Bloodrage cost 20% of max health. The reference's basis table (`0x612c50`, reached from `GetPowerCost` `0x6e31b0`) reads the caster's fields:
| power type | basis |
|---|---|
| health | base health (`UNIT_FIELD_BASE_HEALTH`, 163) |
| mana | base mana (162) |
| rage | 1000 |
| focus, energy | 100 |
| anything else | 0 |
`cost_basis` now holds that table, and `power_cost_at` reads through it for the tooltip, the press-path gate and the action bar. The spell tooltip's rebuild inputs watch base health in place of max health, for the player and the pet. Tests pin each type's basis, and Bloodrage on real data: "337 Health" at level 60, whatever the gear.
Fixes#604
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Sam <samuv.eth@gmail.com>
A roster packet set a member's online bit only for someone new. So a member with a pet who logged off out of view kept answering `UnitExists("partypet1")` and `UnitBuff("party1", i)`, and the party pet's `UNIT_PET` fired on online flips.
The reference's list handler reseats every member through `0x4e82d0`. That keeps the saved record and sets bit 0 from the row's non-zero status byte (`0x4e8361`-`0x4e837b`; raid twin `0x4ba947`-`0x4ba960`). `UNIT_PET` fires only when the stats diff sees the pet guid move (`0x5e57e9`).
Each list now sets every known member's online bit. The `UNIT_PET` edge follows the pet guid unfiltered, and the no-object `UnitIsConnected` reads the record (`0x517dd3`).
Test: a status-only offline list clears the pet and buffs with no `UNIT_PET`, and an online list restores them.
Fixes#666Fixes#665
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The first half of #448 taught the unit-token resolver `partypetN` and `raidpetN`. The per-token unit snapshot that `UnitExists`, `UnitName`, `UnitHealth` and the other getters read still pushed neither. So the stock party pet frames never showed: `PartyMemberFrame_UpdatePet` shows the pet frame on `UnitExists("partypet"..id)`, and `SHOW_PARTY_PETS` defaults to `"1"`.
In the reference:
- **`UnitExists`** (`0x515fb0`) answers 1 for a unit the client holds. It also answers 1, through the roster fallback, for a party member's pet guid cached behind the owner's online bit (`0x4e80a0`) and for a raid row's pet (`0x4bafd0`, gated on the row's online bit at `0x4bb040`), with no object at all.
- **The getters** read, in order: the live descriptor, the party or raid record (`0x496400`), then the pet record (`0x496420`). The pet record holds health `+0xdc`, max health `+0xde`, power type `+0xd8`, and power and max power `+0xe0`/`+0xe2`, the power divided as the live path does.
- `UnitIsConnected` is 1 on any pet-record hit (`0x517dfb`).
- `UnitLevel` and the dead and ghost predicates have no pet leg.
- **Events:** the unit-token router `0x515c50` fires each unit event once per token naming the unit, `partypet%d` and `raidpet%d` included. The stats handler `0x5e5720` fires `UNIT_PET` for the owner on the pet-guid bit.
Changes:
- `ui_party/pets.rs` pushes a snapshot per `partypetN` and `raidpetN`. It comes from the pet's store while held, else from the owner's record, and the existing transitions fire each token's `UNIT_*` events.
- `UNIT_PET` fires with the owner's token when that owner's pet guid changes. The feed's change gate now watches the members' pet stores.
- The despawn snapshot copies the pet's cached name into the member's record (`0x5f0a63`-`0x5f0a70`), so `UnitName("partypetN")` answers for a pet out of view.
- `partypet1..4` get portrait slots. A held pet bakes like `"pet"`. An unheld one that the owner's record names shows `TemporaryPortrait-Pet` (`0x525cb0`).
Tests:
- `ui_party/pets.rs` covers the held-pet and record getters, an offline owner, `UNIT_PET` off the record and off a held member's `SUMMON`, and `UNIT_HEALTH` with the pet's token.
- It also covers raid rows with an offline row's pet.
- `the_stock_party_frame_shows_and_hides_its_pet_frame` loads the default UI and checks that `PartyMemberFrame1PetFrame` shows and hides on dismiss.
- Two portrait tests cover the slots and the stand-in.
Fixes#448🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The stock video options window (`OptionsFrame`, off the player's chain) now opens, saves, restores defaults and cancels with no Lua error, as on 1.12.1.
- The CVars it reads are registered at the reference's defaults: `SmallCull` "0.04" (`0x68854a`), `shadowLevel` "1" (`0x6885bc`), `baseMip` "0" (`0x6887aa`), `DesktopGamma` "0" (`0x402d4d`), `spellEffectLevel` "2" (`0x688900`), plus `doodadAnim` and `texLodBias`, which the new getters read. `SetWorldDetail` keeps `SmallCull` in step (`0x488e56`), and the wrong comment that called the getter its only reader is gone.
- `spellEffectLevel`'s handler (`0x689510`): the value is clamped to 0-2, "Spell effect level set to %d." is printed, the particle emission scalar is set to 0.33/0.66/1.0, and the shard emitter's rate follows the level (`0x6eb95e`).
- The 21 functions #337 lists: the six video getter/setter pairs (`0x488ec0`-`0x489300`), `GetNumFrames`/`EnumerateFrames` in creation order (`0x705f00`, `0x705f60`), and the client queries, including `GetDebugStats` and `OpeningCinematic`'s empty `CMSG_OPENING_CINEMATIC` (0xf9, `0x48c8c9`).
Verified: a headless test walks the stock window's 18 boxes and 9 sliders, then Okay, Defaults and Cancel, with no error (it fails on main at `OptionsFrame.lua:146`), plus unit tests for each binding and handler; 12 mutations each fail a test. A live run opened the window, saved, restored defaults and cancelled with no Lua error. `scripts/gates.sh` green. Built on macOS; no platform seam touched.
Fixes#548Fixes#337
Refs #329 (benilla's own options window has no Spell Detail row yet)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
`SendChatMessage`'s language argument is spoken, as in 1.12.1: a racial language picked from the chat menu (`ChatFrame.lua:2404`, passed on by `ChatEdit_SendText` at `:1950-1954`) or named by an addon goes out in `CMSG_MESSAGECHAT`, where before every line went in the faction tongue.
- `0x49f1e0` starts from the speaker's default language (`0x5ec890`); when argument 3 passes `lua_isstring` (a string or a number) it is matched by name against every `Languages.dbc` row, case-insensitively (`0x49f8a0`, `SStrCmpI`), and a miss raises "Unknown language" (`0x49f2e1`). nil, an absent argument, a table or a boolean keep the default. A language the character has not learned is sent and left to the server, which drops it (vmangos `ChatHandler.cpp:175`).
- The packet builder writes the type, the language and a target for a whisper or a channel only, then the text (`0x49f6c3`-`0x49f72a`); fourteen per-type writers become one, with byte-exact goldens.
- Each new UI state is seeded with the language table.
Checked live against the local vmangos: a say, a yell, a whisper to self and a GM command round-trip through the new builder; a channel line reaches the server's channel lookup; an unknown language raises in Lua.
Fixes#164
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
With Resurrection, Redemption or Rebirth armed and nothing selected, the targeting cursor takes a released party member's corpse: it lights over the corpse in range, and a click casts on it. Before, the cursor stayed grey over a corpse and a click bound nothing.
- **The pick** (`0x480816`, `0x6e6260`). While targeting, a corpse is a candidate only under a word in `0x8600`: under `0x8000` a corpse that is not bones and passes `0x6067d0`, and under `0x200`, tried only without `0x8000`, one that is not bones and fails it. Outside targeting every corpse stays a candidate, as before.
- **The reaction gate `0x6067d0`**: the caster's faction template toward the corpse owner's race template (`ChrRaces`, as `0x5d7120` reads it), friendly at 4 and up. The faction catalog now carries each race's template, and the PvP team loader reads it from there.
- **The cursor**: `0x6e6460`'s corpse leg (`0x6e6719`-`0x6e676d`) with its range tail. `GetMinMaxRange 0x6e3480` pads a corpse like a unit, reading the caster's own reach twice (`0x6e3605`-`0x6e361e`).
- **The click**: `BindTarget`'s corpse arm (`0x6e5f89`-`0x6e6020`), the `0x8000` arm then the `0x200` arm, through the same range merge as a unit (`0x6e602c`). Out of range raises the error and keeps the cursor armed, as the unit arm already does.
- **The wire**: `CMSG_CAST_SPELL` with the corpse bit and the corpse's packed guid, which the client writes for any mask bit in `0x8a02` (`0x7e4e10`) and vmangos reads for either corpse bit (`SpellCastTargetsInfo.cpp:156-157`); `CMSG_USE_ITEM` the same, for Goblin Jumper Cables.
Checked: byte-exact goldens for both packets; unit tests for the pick filter, the cursor verdict (bones, a hostile corpse, out of range, the reach pad), the bind arms from a world click to the sent command, and the reaction gate on the shipped DBCs. Each fails with its piece undone. There is no live run: the probes cannot aim or click in the 3D world. Gates green on macOS; no platform seam touched.
Fixes#450🤖 Generated with [Claude Code](https://claude.com/claude-code)
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>
A ghost could swing, got a lit action bar, a sword cursor over enemies, and an Attack button that did not refuse. benilla tested death as health 0 only, and a released ghost has health 1.
Fixes#246. Fixes#248. Fixes#250. Fixes#251.
- **One predicate** (`0x605f30`): dead or ghost is health 0 or below, or a player with the `PLAYER_FLAGS` ghost bit `0x10`. It lives on the object fields and every site uses it: the attack check (`0x612e10`), the usable walk's first check (`0x6e3dad`), summon, trade and the death screen.
- **#248:** the cast ladder refuses a dead or ghost caster with `SPELL_FAILED_CASTER_DEAD` and sends nothing, unless the spell's `Attributes` has `0x800000` (`0x6e4c49`-`0x6e4c68`); the Attack action button takes it first ("You are dead").
- **#251:** the sword cursor also needs a live, unmounted, unpacified player in control (`0x482648`-`0x4826cb`). A right-click now decides attack from the reference's CanInteract/CanAttack fork (`0x60c18c`-`0x60c247`), not from the cursor kind, so a ghost right-clicking a hostile NPC with a service flag selects it and does nothing else, instead of opening its window.
Tests: seven tests, each with a ghost at health 1; `scripts/check.sh` is green.
To see it: release spirit. The action bar stays grey; Attack Target reads "Can't attack while dead."; hovering a hostile mob shows the pointer; right-clicking a hostile vendor selects it and opens nothing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The second read of `benilla-protocol`'s comments, the last step #41 asked for: that crate's comments were rewritten to the rule before second readers existed. Four readers compared every file's comments against their state before the rewrite and against the code as it is now.
Fixes#41.
- **Citations.** vmangos line citations are re-pointed to the pinned revision: off-by-a-few lines (`Pet.cpp`, `Guild.cpp`, `Petition.cpp`, `LootHandler.cpp`, `ChatHandler.cpp`), and paths the rewrite dropped where a bare file name is ambiguous (`Server/Packets/Spell.cpp` against `Spells/Spell.cpp`, the two `Item.cpp`, `Group.cpp` and `Chat.cpp`). The gossip-hello citation is `NPCHandler.cpp:347`.
- **Facts restored.** The move-time-skipped chain (`0x603b40` → `0x601560` → `0x61ab90`), the addon-message TAB surviving vmangos's chat sanitizer, the zone-under-attack sender, `SMSG_ADDON_INFO` answering the auth session's addon block, the officer-note permission gate, and `SMSG_ITEM_COOLDOWN` on equipping an item with an on-use spell (the old text said a proc).
- **Deviation labels.** A label now carries its reason, or goes when the behaviour is only unbuilt (the survey window, the group XP bonus, the NPC-text language garble).
- **Two examples.** `park_probe` and `login_refusal_probe` took a hard-coded local account; they now read `WOW_USER` and `WOW_PASS`.
- **Verification.** Every file strips to identical code apart from the two examples; `cargo fmt --check` is clean.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Part of #41: the fourth of five `benilla-app` pieces. This one is capture and its probes, sound, the network layer and remote movement, spells, and portraits. Their comments are rewritten to the rule in `docs/METHOD.md`, which is what the code does and the reference fact behind it, in a line. 23,383 comment lines become 9,669.
Fixes#35. Fixes#110. Fixes#111.
- **The mechanical strip.** The citations that were only a private record number go first, and each edit is shown to be a pure removal.
- **Wrong facts corrected.** The rewrite corrects the comments that stated wrong facts. Among them:
- The probes' run blocks pointed at tooling outside this repository; each now points at `docs/CONTRIBUTING.md`, "Running it unattended". The protocol examples show placeholders for an account's password.
- The dismount kit's name-match string is `SpiritWolf (DONOTRENAME)` (`0x8627bc`); the stun and jump-start vocals are never dispatched, and jump-end finds no kit in the shipped data.
- The cast bar's flash and fade step once per `OnUpdate` (`CastingBarFrame.lua:132-147`); there is no 30 Hz normalisation.
- vmangos sends the OK cast result before the GO (`Spell.cpp:3681`, `:3715`), and a creature can levitate from a script (`boss_onyxia.cpp:679`).
- A live unit whose model is not ready has a blank portrait in the reference (`0x519fcc`); the stand-in path is for a unit with no object.
- Docs sitting on the wrong item, removed names, and vmangos line citations checked against the pinned revision.
- **Deviation labels.** "Deviation:" now marks only a choice with a reason. An unbuilt behaviour, or one whose reference side is untraced, says so plainly.
- **Verification.** Every file strips to identical code, apart from two test literals in `net.rs` that now use placeholder account names, and `cargo fmt --check` is clean. Six second readers compared every file old against new, restored the facts the rewrite had dropped, and checked each new citation against the code, the stock files, vmangos and the reference.
Behaviour differences the rewrite surfaced are filed as their own issues (#319, #324, #329, #330 and #331 among them). String literals are untouched; they are #92.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Test fixtures pass "player"/"secret"; the run lines in `.cargo/config.toml`, the protocol
examples and the auth and world binaries show placeholders; the SRP probe example takes
--user and --pass instead of defaulting them. Built on macOS.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- OptionsFrame.xml and options_tests.rs: the stock camera-style dropdown writes "0" for Never
(UIOptionsFrame.lua:525,536,547), not "3"; the `alt` entry only shows a stored "3" as Never.
- unit/bindings.rs: TargetByName's silent miss is a gap (#52), not a deviation; the reference's
messages are 0x127 ERR_UNIT_NOT_FOUND and 0xb8 ERR_GENERIC_NO_TARGET.
- fields/unit.rs: the melee reach's 5.0 is a floor (0x6e35bf-0x6e35ce), not a cap.
- tests/nameplate.rs: pfUI's click-through is nameplates.lua:1228.
Comments only; code unchanged. Built on macOS.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Part of #92, for the crates whose comment pass has landed and whose literals are few: `benilla-assets`, `benilla-blp`, `benilla-protocol` and `benilla-srp`.
- Assert messages, printed labels and a probe's error text drop their private record and bug numbers and the workspace's name for the maintainer. Each keeps its fact in its own words. One assert names a client function by its address, `0x68a830`, instead of a disassembler's label for it.
- Two terrain tests named after a bug number are renamed for what they check: `the_pin_stands_one_chunk_west_of_an_impassable_band` in `benilla-formats`, and `a_body_walking_east_from_the_pin_is_stopped_at_the_wall` in `benilla-world`. Those two crates' other literals follow in their own pass.
- Every change is to string-literal text, proven with comments stripped and every literal masked, except the two renamed tests.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Fixes#32. Every vmangos `File.cpp:N` citation in the crates whose comments have been rewritten now reads in one revision, vmangos core `6b34a36`, the one the comments are written against, a few commits from the server benilla is run against. Some citations had been taken from a newer vmangos checkout, where the lines have moved. #32's own targets came from that newer checkout too, so where this PR and #32 differ, this PR follows `6b34a36`.
- 53 citations in 31 files are re-pointed: most in benilla-protocol, a few in benilla-ui and benilla-app. Each new line was read and is the construct its comment names.
- #32's cases:
- The root-ack kick is `MovementHandler.cpp:715-722`; three comments cited the falling deferral after it.
- Movement is discarded before `CMSG_SET_ACTIVE_MOVER` lands at `:291-293`, through `Player::GetConfirmedMover`.
- The released mover's parting stop is `:955-964`.
- The mount-special echo is sent with `self` false at `:972`. Whether the sender gets its own echo depends on the server's broadcaster (`Object.cpp:2273-2280`); that is stated once, where the packet is parsed, and the opcode comment points there.
- Ten more citations were a line or two off in every revision. One comment also stated a wrong fact: vmangos's ignoring-you party refusal names the invitee, and the empty name is the raid-convert confirmation's.
- Comment text only. Every file strips to identical code, and `cargo fmt --check` is clean.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Thirteen now assert what they claimed:
- every bare trade status, and the 444-byte extended snapshot for
empty, full and mixed slots;
- the status-1 and status-3 battlefield tails;
- every quest-share verdict byte through encode, parse and decode;
- the greeting pick itself, and the whole compressed-move batch.
Eleven are renamed to what they check, where the claim had nothing to
check against: no capture bytes, no production opcode list, no server
encoder. No strengthened assertion failed.
Probe and assert messages drop their record numbers. The aura probe's
refusal message no longer claims the level-6 probe accounts need a
grant for a level-4 command.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
vmangos always sends 1.0, meaning none (Player.cpp:3039), so 1.12
shows no group-bonus line against it either.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1,065 comment lines become 340; the code is unchanged. Corrected:
- CMSG_CANCEL_CAST carried CMSG_CANCEL_AURA's doc;
- the inspect reply is parsed, then dropped;
- mount failures reach the player as error lines, so they are no
longer a deviation;
- the pet-stable note moves from SMSG_INVALIDATE_PLAYER to the stable
constants.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1,040 comment lines become 387; the code is unchanged. The note that
item objects have no decode path is gone, since the same file decodes
them.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1,039 comment lines become 472 across 19 files; the code is unchanged.
The movement test's claim that write() never serializes a transport
tail is gone: it does.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1,071 comment lines become 370 across 23 files; the code is unchanged.
The Warden refusal and the billing-time default now carry their reasons.
A gap note on cyclic splines described the app, not this crate, and is
gone.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1,081 comment lines become 459; the code is unchanged. Corrections:
- MonsterMove's description sat atop MoveTimeSkipped's doc and
documented the wrong variant; it is back on MonsterMove.
- GossipMenu's tuple doc gains its missing level.
- Four false claims are gone: "only primitives" on SessionEvent, a
code field LoginFailed does not have, a broken object_scale link,
and "filled from nothing else" on SpellChainTargets.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
812 comment lines become 264; the code is unchanged. JumpInfo's doc
called zspeed up-positive, against its own captured fact and every
consumer, which negate it; the up-positive formulas are gone.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1,079 comment lines become 390; the code is unchanged. Corrected
against the code:
- area spirit healers are modelled;
- the resurrect name length is skipped, not cross-checked;
- SMSG_CHAT_WRONG_FACTION is handled in parse.rs, not chat.rs.
AFK/DND clearing in the member snapshot matches the reference and is no
longer called a deviation.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1,071 comment lines become 573; the code is unchanged. The world
probe's field docs are its --help text, so the help is shorter now and
matches what each flag runs: --quest takes quest 783 from Willem to
McBride, --quest-item needs the starter item to survive, --giverstatus
queries once, --spells makes three casts. Also corrected:
- the aura-duration packet has a SessionEvent;
- the SRP xor hash is SHA1(N) XOR SHA1(g), not a hash of it;
- the cooldown probe picks Tri, else the first character.
benilla sending a stored integrity hash instead of hashing the install
is now marked as a deviation.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1,082 comment lines become 487; the code is unchanged. The creature
query doc said the display id was dropped; CreatureQueryInfo keeps it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
514 comment lines become 183; the code is unchanged. Three comments
said something other than their bytes:
- SMSG_NEW_WORLD's orientation is -0.5, not 0.5;
- transport 176495 is the Grom'Gol-Undercity zeppelin, not the
Menethil-Theramore ferry;
- 176244 is the Moonspray, the Auberdine-Rut'theran boat, not the
Orgrimmar-Undercity zeppelin.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1,061 comment lines become 396; the code is unchanged. A spell test's
comment described the unit-target shape while its assert checks the
self-cast one; it now describes the self-cast shape.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1,096 comment lines become 372 across 31 files; the code is unchanged.
Dropped as false or stale:
- the module table, which missed 8 of the 44 modules;
- "cacheable forever" for names, which a pet rename breaks;
- "only failures get a packet", though SMSG_BUY_ITEM answers a buy;
- a go_target parameter that does not exist;
- "three" cast shapes, where there are five.
vmangos line citations now name the function or the current lines.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
959 comment lines become 400; the code is unchanged. The read-enchant-
time doc had run into the next function's, so rustdoc gave it to
read_open_container; it is back on its own function. MaxCount is no
longer called account-wide.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1,031 comment lines become 320; the code is unchanged. A guid test
called transport 176495 the Menethil-Theramore ferry. The world
database names it the Grom'Gol-Undercity zeppelin.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
760 comment lines become 262; the code is unchanged. One doc said the
opposite of its code: corpse_look is None when either BYTES word is
missing, not neither. The ObjectFields doc had drifted onto CorpseLook
and is back on its struct.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
404 comment lines become 168; the code is unchanged. Two claims were
wrong and are corrected: the world-state probe needs no temporary GM
grant, since the probe accounts carry level 6 and the command needs 5.
The root-ack citation now points at the current vmangos lines.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Each item says what it is and the wire or server fact behind it, with
the vmangos or client citation; the two kept deviations say why.
History, record numbers and emphasis go. With comments stripped the six
files are identical.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
One line per dependency where the reason is not obvious, measurements
kept as the number and the unit. Parsed with tomllib before and after,
every manifest is identical.
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>
- a Vanish, a stealth or a unit leaving range clears your target at once, not two seconds later, and TAB reaches a mob behind you (2345)
- a fully painted terrain layer covers fully: roads and rock no longer let about 6% of the grass underneath show through (2345)
- companion pets show their names, the saved camera pitch survives a login, and a missed resurrect offer no longer blocks later ones (2345)
- ESC on a quest giver closes it, browsing the auction house by category searches the right items, and abandon removes the quest you chose (2345)
- a profession window open at logout no longer reopens for the next character (2345)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- a creature walking a path no longer cuts its first corner: the path's first waypoint was dropped at decode (2342)
- two characters whose names differ only in accented or non-Latin letters no longer share macros, bindings and SavedVariables; a file that failed to load is not overwritten at logout (2342)
- custom chat channels survive a logout, a collapsed quest header keeps its quests watched, and a trackpad swipe scrolls as far as it adds up to (2342)
- a hearth off a zeppelin no longer lands back on its deck, and an opened lockbox with loot left in it unlocks (2342)
- every snapshot runs on Vulkan, in a container, before it ships (2344)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- an item is an object in the one index, and its enchant and lifetime countdowns are its own (2334, 2340)
- the server's stand state applies, a bag equipped into a bag slot fires BAG_OPEN, and the inspect echo is dropped on purpose (2339)
- the schedule census counts declared orders only, and the architecture walls gate leaks rather than the API (2337, 2338)
- one queue for every event into the UI is not built: the reference orders its events per mechanism, not by the wire (2341)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- the cast ladder moves under the spell: try, target bind, the usable walk and the refusal rungs live in one place, and the cast reply sends a chained cast itself (2330)
- every server packet decodes through one exhaustive match, and an opcode-coverage script joins the reference's 387 handled opcodes against ours (2331)
- a landing that touches a platform seam compiles Linux and Windows first, and the seven WMO portal-cull audits join the tests (2331)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- the spell owns its lifecycle state: the in-flight cast, the local cancel, the cooldowns and the spell-modifier tables live in one module (2328)
- a malformed MPQ, DBC, M2 or WDT file is refused instead of crashing the client, nine read sites bounded
- a test that needs the install or the addon corpus fails instead of skipping when the data is there; the Bagnon render suite runs again (2329)
- the dev crash injector is armed on every platform, and no instrument writes a path relative to the working directory
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- the CVars are one engine-side table that outlives every interface reload: a change fires its observer, the eight latched rows wait for RestartGx, and /console gains set, cvar_reset, cvar_default, cvarlist and help (2303)
- every push into the interface runs in one feed phase after the net drain and before the tick, held by a structural test on the built schedule (2304)
- subsystems own their packet handlers, dispatched in packet order; the auction house is the first family out of the 273-arm drain (2305)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- inside a battleground the battle map draws its terrain, overlays, arrow and blips: the world map's selection carries the instance maps as the reference's third cell (2298)
- talent spell modifiers land: the 45 packets a level-60 login threw away fill the reference's two tables, and a spell's power cost reads them, so a cast you can afford is no longer refused (2298)
- a ghost's Accept on the spirit-heal dialog can no longer be eaten by frame order, and a latched spirit guide no longer follows you into the next character's session (2298)
- the battleground probe refuses GM mode, exits when done, and reads the scoreboard before toggling it (2298)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- the character-create and main-menu backdrop runs its material animation: the clouds drift on their 20, 30 and 40 second loops, which were seeded once and never sampled (2300)
- Arathi Basin and Alterac Valley are entered and censused beside Warsong Gulch, the flag is picked up, and a match runs to its end (2296)
- the animation variation roll is one clock-seeded stream, as the reference's C runtime is, not four streams seeded 0 (2299, 2301)
- a cancelled channel never turns the bar red and a finished one closes on the bar's own clock, now pinned by tests that drive the real packet sequence (2284)
- the field watch fires one edge per moved descriptor dword, from the merge that holds both sides (2297)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>