Compare commits

...
Author SHA1 Message Date
warren 5385b14e3a Add atomic account Boss Card checkpoints and preserve cards in legacy saves (#7) 2026-10-10 01:59:50 -04:00
phenom ff20ab8779 Update Healer Man server 2026-10-07 13:05:04 -04:00
phenom 69809f7228 Update Healer Man server 2026-10-06 22:25:34 -04:00
phenom 6114a2295f Update Healer Man server 2026-10-04 22:51:21 -04:00
phenom 6cc1b9217f Update Healer Man server 2026-10-04 13:13:35 -04:00
phenom 39458d5de6 Update class mechanics, stat rulesets, and CoA reference catalogs 2026-10-04 12:56:30 -04:00
phenom b16821e92e Update Healer Man server 2026-10-02 10:38:12 -04:00
phenom 4c768fbec6 Update Healer Man server 2026-09-30 13:25:55 -04:00
phenom 4fb7a0b9c8 Update Healer Man server 2026-09-30 09:57:13 -04:00
phenom 35dfdaed61 Update Healer Man server 2026-09-28 22:46:45 -04:00
phenom 9d7e0e2f9e Update Healer Man server 2026-09-27 21:48:00 -04:00
phenom 15a5254380 Update Healer Man server 2026-09-27 18:46:30 -04:00
phenom e284f4fc76 Update Healer Man server 2026-09-27 14:31:15 -04:00
1528 changed files with 3687680 additions and 34174 deletions

No files matched your search

+6
View File
@@ -23,3 +23,9 @@ dist-android/
.web-public/
__pycache__/
*.pyc
# Local CoA reference downloads and immutable generated snapshots.
/data/coa-reference/cache/
/data/coa-reference/snapshots/
/data/coa-reference/current.json
/data/coa-reference/.current-*.tmp
+3
View File
@@ -0,0 +1,3 @@
import { ROM_ALL_ABILITIES } from "./src/game/romAbilityCatalog";
console.log("total", ROM_ALL_ABILITIES.length);
console.log(ROM_ALL_ABILITIES.filter((entry) => entry.effects.some((effect) => effect.kind === "heal" || effect.kind === "hot") && entry.castMode === "channel").map((entry) => `${entry.id}: ${entry.name} (${entry.effects.map((effect) => effect.kind).join(",")})`).join("\n"));
+33
View File
@@ -61,6 +61,39 @@ These rules apply to every change under this project root.
- CoA specializations and RoM class/role builds are Needs Testing. They may be inspected in an explicit targeted diagnostic, but must not enter random, all-eligible, regression, bracket, or NPC seat-audit runs.
- A broader balance run requires an explicit user request or a readiness-policy promotion. Record that expanded scope in the task handoff.
## Default test dungeon
- Use **Stormwind Stockade: Cellblock Rush** (`bite-sized-stormwind-stockade`)
for new routine gameplay, mechanics, healing, party, camera, input,
performance and browser diagnostics. This is the project owner's default as
of 2026-10-05. Each fresh run deterministically selects one of the five
Stockade bosses from its shared run ID; live evidence must record the boss
actually selected rather than assume Hamhock.
- Shared playtest defaults belong to `scripts/playtest-defaults.cjs`; the current
workflow and evidence requirements are in `docs/TEST_DUNGEON_POLICY.md`.
Install/verify the shared Stockade content pack through the normal entry flow
when needed. The full `stormwind-stockade` campaign is only for an explicitly
selected source-specific or full-clear task; reusable harnesses must use the
`FULL_STOCKADE_*` constants and require an explicit route or opt-in flag.
- Do not choose Wailing Caverns for new routine live tests. Retain its existing
source-specific unit/import fixtures and historical reports as evidence, but
they do not override this default. A new Wailing live run requires an explicit
user request for that dungeon.
- Preserve incident-specific historical evidence from other dungeons. When
investigating a report tied to another dungeon, inspect that exact source;
use Cellblock Rush for generic validation and follow the user's requested
dungeon for any separately authorized encounter-specific reproduction.
- This fixture choice does not promote Needs Testing builds, broaden balance
certification, change the level-80 cap, or authorize loot wiring.
## Mechanic subprocess preference
- When delegating the owner's mechanics work, use `gpt-6-luna` with `xhigh`
reasoning by default. A higher-tier subprocess model requires the owner's
explicit permission; do not silently upgrade because a task is difficult.
- Divide independent mechanics where practical, coordinate shared runtime files
and the production build, and keep user updates brief.
## Playable characters and equipment
- `src/avatar/CharacterModel.tsx` is the shared player, party, roster, and character-creation rendering path. Never replace it with a screen-specific loader.
+1657
View File
File diff suppressed because it is too large. Load diff
+51 -1
View File
@@ -6,6 +6,13 @@ WMO, all 3,381 active default-set doodad placements, reconstructed WMO water,
separate collision, authoritative entrance/encounter anchors, and a responsive
exploration HUD modeled after the architecture of `i-want-to-heal-mmo`.
New routine live gameplay and mechanics QA uses **Stormwind Stockade: Cellblock
Rush** (`bite-sized-stormwind-stockade`). Each run selects one of the five
Stockade bosses from its shared run ID. See [the test-dungeon policy](docs/TEST_DUNGEON_POLICY.md)
and `AGENTS.md`; full Stockade campaigns require explicit selection, while
Wailing's source-specific fixtures and dated evidence remain historical
references.
## Run
```powershell
@@ -194,6 +201,46 @@ The dungeon, Manastorm, and Runewaker environment optimizers apply the same
KTX2 step to future visual outputs. The production build also runs the audit so
an accidentally reintroduced PNG/JPEG world texture fails before deployment.
## RuneWaker dungeon environments
`scripts/runewaker-pipeline/README.md` documents the source import and package
workflow. For Sand Vortex, the WDB has native terrain `header`, `chunks`, and
`texture_list` tables even though it has no terrain ROS. The recipe selects the
nine 480-unit chunks intersecting the encounter bounds instead of generating a
flat arena from prop bounds. Each chunk retains the source heightfield, native
triangle layout and visibility masks, packed source normals, normalized XZ
weight-map UVs, and its original DXT1 splat maps. The RGB channels map to the
chunk's original Viper Canyon DDS tile layers and `texture_list` scales; they
are blended at runtime rather than baked into oversized per-chunk images.
The extraction manifest and source buffers are regenerated by
`node scripts/runewaker-pipeline/sand-vortex/extract-native-terrain.mjs` under
the ignored `runewaker-export-work/sand-vortex/native-terrain-source/`
directory. `scripts/runewaker-pipeline/build-environment.mjs` incorporates the
native terrain visual and collision into the Sand Vortex package. The loader
adapter in `src/scene/runewakerTerrainMaterial.ts` resolves the GLB's auxiliary
texture variants and blends the source layers with the original tile scales.
Run its focused parser/topology checks with:
```powershell
node --test scripts/runewaker-pipeline/sand-vortex/extract-native-terrain.test.mjs
```
The Origin now includes native terrain chunk `[2,2]` around its reviewed source
path entry. Its source heightfield, triangle visibility, normals, four tile DDS
layers, tile scales, and two DXT1 splat maps are preserved; 8,146 visible ground
faces are packaged for collision and navigation. The chunk's 30,332-byte water
payload remains unparsed, so the recovery covers ground only. The runtime entry
uses source path graph 1026 node 854 while retaining the original Lua spawn and
direction as provenance. Two short ordinary walking legs passed on native
ground; party routing farther inside and full collision certification remain
outstanding.
The all-dungeon lighting profiles in `src/game/runewakerDungeonEnvironment.ts`
and their entrance/High-shadow targeting provide reviewed runtime approximations.
The static RoM import does not carry original WDB light components, so those
profiles do not claim to reproduce client-authored light objects.
## Controls
- Move: WASD, arrow keys, or left stick
@@ -298,6 +345,9 @@ use the collision GLB directly.
- `src/ui/`: responsive HUD, encounter map, loading, pause, and error surfaces
- `src/assets/game/dungeons/wailing-caverns/`: shipping GLBs and anchor metadata
Wailing Caverns remains the global-WMO regression fixture. Deadmines is the
Stormwind Stockade: Cellblock Rush is the default live test dungeon. Wailing
Caverns retains its existing global-WMO import/source fixtures, which do not
select routine QA.
Deadmines is the
gated ADT/hybrid pilot and cannot be enabled without authoritative server data
and green automated/visual reports.
+29
View File
@@ -0,0 +1,29 @@
# CoA offline reference
This directory holds the local-first CoA reference dataset and the evidence for
explicit active-catalog promotion. Historical reference builds and active
promotion are separate commands.
Run `npm run coa:reference:build` from the project root. The command reads the
existing Ascension client, extracted base-client DBCs, and HealerMan's July talent
snapshot. It never downloads anything or writes to those sources.
`current.json` points to a verified immutable directory under `snapshots/` with
`reference.json`, `audit.json`, `audit.md`, and a checksum manifest. Downloaded
archive supplements live under `cache/`. These generated files are local and
ignored by Git. The lossless July baseline under `baselines/`, the active
`promotion-report.json`, pipeline, tests, and usage documentation are tracked.
Use `npm run coa:reference:fetch` explicitly to cache the pinned August talent
archive, then rebuild to include its comparison. The supplement remains separate
from the primary July/local-client reference dataset.
`npm run coa:reference:fetch:spells` selectively caches missing global BASE spell
records and their linked payloads. `npm run coa:reference:promote` validates the
cached August Vol'Jin trees and local/global spell evidence, then updates the
active CoA catalog offline. Follow it with `npm run coa:catalogs:refresh` to
regenerate CoA runtime/UI shards and missing icons. Classic catalog records and
progression identities are protected; CoA readiness remains Needs Testing.
See [the pipeline guide](../../docs/COA_REFERENCE_PIPELINE.md) for source roots,
lookup examples, validation, failure handling, and version limitations.
+1
View File
@@ -0,0 +1 @@
{"candidateSha256":"9208e973c43c31d263fb429f7ab82a2cc6732e2a70bc14f482b6428c9b296091","gaps":{"missingBaseProgressionRankCount":13,"missingBaseProgressionRankIds":[501862,501863,501864,501865,501918,501919,501920,501922,501923,501924,501925,502889,560469],"missingBaseSpellCount":224,"missingBaseSpellIds":[3042,7015,7016,10238,116863,116936,117041,117066,117069,117151,117284,117490,120241,120248,120270,120614,120640,120692,120919,121208,121300,121404,122206,122296,122388,122452,122507,300070,400544,500017,500019,500025,500029,500030,500032,500037,500084,500088,500122,500145,500148,500155,500197,500332,500366,500565,500909,500921,500922,500942,500948,500949,500954,501361,501862,501863,501864,501865,501918,501919,501920,501922,501923,501924,501925,502612,502889,503215,506002,524988,555377,560137,560469,704095,704134,704140,704160,704376,704480,704507,704572,800053,800183,800232,800264,800268,800271,800312,800314,800369,800377,800383,800411,800429,800433,800445,800455,800467,800535,800570,800582,800625,800713,800718,800720,800721,800725,800745,800746,800747,800748,800777,800853,800883,800885,800888,800896,800897,800900,801239,801250,801267,801296,801298,801321,801329,801330,801408,801587,801605,801606,801647,801648,801651,801671,801673,801675,801681,801682,801684,801694,801715,801750,801762,801764,801810,801819,801822,801845,801846,801896,801937,801944,801965,801993,801995,802010,802012,802077,802116,802123,802127,802288,802565,802869,802875,802992,803691,803944,803952,803982,804006,804167,804180,804229,804255,804269,804289,804291,804352,804504,804549,804554,804555,804556,804558,804560,804562,804594,804600,804601,805481,805489,805491,805497,805623,805630,805645,805665,805713,805728,805733,805765,805772,805781,805903,806098,806107,806127,806229,806230,806238,806243,806280,806284,806287,806317,806318,806326,806362,806367,806519,806601,7055070]},"nodeChanges":{"added":[{"aeCost":0,"classId":29,"connectedNodeIds":[1788],"description":"Inject an ally with a powerful magic antidote, dispelling 2 curse effects from them.","entryType":"Talent","flags":0,"group":0,"iconBasename":"inv_ascend_potions_02","id":11788,"isPassive":false,"isStartingNode":false,"maxPoints":1,"name":"Mycelial Healing","nodeType":"SpendSquare","rankDescriptions":[{"description":"Inject an ally with a powerful magic antidote, dispelling 2 curse effects from them.","rank":1,"spellId":520153}],"requiredClassPoints":0,"requiredIds":[],"requiredLevel":0,"requiredSpecPoints":0,"sortOrder":0,"tabId":92,"teCost":1,"x":4,"y":2},{"aeCost":1,"classId":25,"connectedNodeIds":[33969],"description":"Your Devour Magic is now instant cast.","entryType":"Ability","flags":0,"group":301010,"iconBasename":"achievement_boss_triumvirate_voidbrokenbrute","id":12012,"isPassive":false,"isStartingNode":false,"maxPoints":1,"name":"Devourer","nodeType":"SpendCircle","rankDescriptions":[{"description":"Your Devour Magic is now instant cast.","rank":1,"spellId":301010}],"requiredClassPoints":9,"requiredIds":[],"requiredLevel":0,"requiredSpecPoints":0,"sortOrder":0,"tabId":87,"teCost":0,"x":2,"y":6},{"aeCost":0,"classId":25,"connectedNodeIds":[1375],"description":"Increases the duration of Psychic Suppression by 1 sec and Eldritch Devastation by 2 sec.","entryType":"Talent","flags":0,"group":301008,"iconBasename":"5_druideskill20_border","id":13957,"isPassive":false,"isStartingNode":false,"maxPoints":1,"name":"Dark Channeler","nodeType":"SpendCircle","rankDescriptions":[{"description":"Increases the duration of Psychic Suppression by 1 sec and Eldritch Devastation by 2 sec.","rank":1,"spellId":301008}],"requiredClassPoints":0,"requiredIds":[],"requiredLevel":0,"requiredSpecPoints":8,"sortOrder":0,"tabId":65,"teCost":1,"x":4,"y":7},{"aeCost":0,"classId":12,"connectedNodeIds":[6739,12739],"description":"Removes the cast time of Crush, but its damage is reduced by -25% and it no longer stuns the enemy.","entryType":"Talent","flags":0,"group":807183,"iconBasename":"inv_hammer_1h_jiro_b_01","id":14265,"isPassive":false,"isStartingNode":false,"maxPoints":1,"name":"Crusher","nodeType":"SpendCircle","rankDescriptions":[{"description":"Removes the cast time of Crush, but its damage is reduced by -25% and it no longer stuns the enemy.","rank":1,"spellId":807183}],"requiredClassPoints":0,"requiredIds":[],"requiredLevel":0,"requiredSpecPoints":8,"sortOrder":0,"tabId":31,"teCost":1,"x":6,"y":5},{"aeCost":0,"classId":15,"connectedNodeIds":[],"description":"Summons a permanent Shadowhound companion to aid you in combat. Your Shadowhound receives 25% of healing done to you.","entryType":"Talent","flags":1056772,"group":0,"iconBasename":"inv_wolfdraenormountshadow","id":17414,"isPassive":false,"isStartingNode":false,"maxPoints":1,"name":"Houndmaster's Whistle","nodeType":"SpendSquare","rankDescriptions":[{"description":"Summons a permanent Shadowhound companion to aid you in combat. Your Shadowhound receives 25% of healing done to you.","rank":1,"spellId":801343}],"requiredClassPoints":0,"requLine truncated
+11
View File
@@ -0,0 +1,11 @@
# Account Boss Card checkpoints
`PATCH /api/cloud-save` adds an account-scoped checkpoint for Boss Cards without sending a replacement cloud document. The server derives the owner from the authenticated bearer session; request fields cannot choose an account. The body is `{ "bossCards": <raw collection>, "expectedRevision": <nonnegative safe integer> }`.
The server serializes the compare and write in a SQLite `BEGIN IMMEDIATE` transaction. A missing save has revision `0`. A matching request merges the submitted collection with that account’s saved cards, changes only `data.bossCards`, increments the cloud revision, and returns `{ revision, updatedAt, data }`. A stale revision returns HTTP `409` with `code: "revision_conflict"` and writes nothing. The client should reload the current save before retrying. Missing collections and invalid revisions return a client error; malformed collection values normalize to empty under the source policy without removing existing cards; an unauthenticated request is rejected before the body is used.
Normalization and merge behavior match `src/game/bossCards.ts`: the allowed rarities are Normal, Rare, Epic, and Legendary; positive finite counts are floored and bounded by `Number.MAX_SAFE_INTEGER`; invalid/unknown entries are dropped; repeated account copies keep maximum counts. Numeric `time:revision` claim IDs keep the later time and then higher revision; other claim strings use lexical maximum. Map-like output uses null-prototype count/claim records so names such as `__proto__` remain ordinary data keys.
Legacy `PUT /api/cloud-save` remains a full replacement for non-card fields. When either the stored or incoming document has a Boss Cards field, the server max-merges those collections into the incoming document. This keeps old clients that omit or resend stale card snapshots from deleting earned account cards, while their other fields retain the existing replacement behavior. PUT does not gain optimistic concurrency; PATCH is the revision-checked card-only route.
The focused loopback test uses the pinned source server factory, authenticated SQLite accounts, and a temporary database. It covers account isolation, cross-origin PATCH preflight, authorization, normalization, conflict/no-write and retry, concurrent revision checks, stale and omitted-card PUTs, deduplication, and server restart persistence. It does not contact the hosted service or exercise native UI integration.
+237
View File
@@ -0,0 +1,237 @@
# Active class behavior and spell visual audit
Updated 2026-10-03. This is a source/runtime audit of the shipped WoW 3.3.5a and RuneWaker catalogs in Healer Man. It records confirmed gaps and the fixes made in this pass. It is not a claim that every ability has passed a live-game playtest or a screenshot-based visual review.
## Native stat input contract (2026-10-03)
Explicitly native RoM profiles now derive source attributes and HP/MP/ATK/DEF/MATK/MDEF/DMG/MDMG channels from local RuneWaker records, retain source healing and combat-point channels, and carry selected native gear values. Existing saved profiles keep WoW compatibility; the main-menu selector changes each character independently. This supersedes earlier findings that the native stat/input contract was entirely missing. It does not implement the full HolyHeal spell resolver, native hit/critical/avoidance consumers, matchmaking, or RoM readiness promotion. See [the implementation and compatibility boundary](CHARACTER_STAT_RULESETS_2026-10-03.md) and [the source contract](ROM_NATIVE_STATS_SOURCE_2026-10-03.md). Dated class reports preserve their original evidence and remaining per-spell/version blockers.
## Class-mechanics source precedence
- For WoW, use the existing generated class, rank, and talent entries wherever they contain the relevant data. Consult [WotLKDB 3.3.5a](https://wotlkdb.com/) only to fill a missing tooltip or spell detail; do not replace a populated generated value with a conflicting database row.
- For RoM, use populated RuneWaker generated entries and local source mappings as the baseline. When the current [Chronicles of Arcadia Wiki](https://chroniclesofarcadia.com/en/wiki/skills/list) or its patch notes clearly identifies the same ability or an explicit rework, prefer the current CoA behavior over a conflicting RuneWaker value. Verify the skill name and class pairing before treating a reused ID as the same ability. Document the selected source, the conflict, and any simulator approximation; leave missing triggers or values unresolved rather than guessing.
- This mechanics follow-up excludes visual and sound tuning. The visual findings below record work from the earlier visual pass.
## Reviewed scope
- WoW: the ten playable class catalogs, including ability ranks, talent-driven modifiers, and combat-effect coverage.
- RoM: the generated catalog inventory covers all ten primary class catalogs and both sides of each paired-elite row. The regenerated current catalog includes the supplemental learnable Warden 499544 row and contains 932 unique skills (590 active and 342 passive) across 937 rank records; all 932 have resolved icons. The runtime catalog composes 936 ability definitions plus 937 ranked versions (1,873 entries), including four runtime-added definitions. Primary and secondary role associations have been source-reviewed, while executable runtime coverage is selective. The role-association/coverage table below is from an older 929-row snapshot taken before the Druid/Warrior 499956 and Warden 499544 additions; its class totals are historical, not current.
WoW inventory by generated catalog class:
| Class | Ability rows | Rank rows | Rank rows with manifest mapping | Rank rows with original effect graph |
|---|---:|---:|---:|---:|
| Warrior | 51 | 153 | 123 / 153 | 123 / 153 |
| Paladin | 75 | 221 | 169 / 221 | 168 / 221 |
| Hunter | 68 | 194 | 157 / 194 | 125 / 194 |
| Rogue | 42 | 136 | 114 / 136 | 108 / 136 |
| Priest | 56 | 264 | 218 / 264 | 218 / 264 |
| Death Knight | 45 | 77 | 47 / 77 | 47 / 77 |
| Shaman | 62 | 280 | 251 / 280 | 149 / 280 |
| Mage | 78 | 319 | 258 / 319 | 258 / 319 |
| Warlock | 66 | 267 | 224 / 267 | 224 / 267 |
| Druid | 74 | 318 | 283 / 318 | 280 / 318 |
- RoM rows and active-effect coverage by class (primary + secondary roles; historical 929-row snapshot before 499956 and 499544 were added; not current):
| Class | Rows | Active / passive | Active rank IDs with manifest entry | Active rank IDs with original effect graph |
|---|---:|---:|---:|---:|
| Warrior | 204 | 120 / 84 | 118 / 120 | 10 / 120 |
| Scout | 166 | 89 / 77 | 89 / 89 | 28 / 89 |
| Rogue | 207 | 113 / 94 | 111 / 113 | 32 / 113 |
| Mage | 205 | 121 / 84 | 122 / 124 | 28 / 124 |
| Priest | 167 | 103 / 64 | 101 / 103 | 35 / 103 |
| Knight | 123 | 68 / 55 | 68 / 68 | 23 / 68 |
| Warden | 132 | 84 / 48 | 84 / 84 | 1 / 84 |
| Druid | 130 | 80 / 50 | 81 / 81 | 5 / 81 |
| Warlock | 130 | 85 / 45 | 81 / 85 | 9 / 85 |
| Champion | 125 | 87 / 38 | 87 / 88 | 5 / 88 |
Manifest coverage means an effect mapping exists; a graph means an original effect graph can render in the browser. Neither proves the effect is the right size or brightness. Most RoM entries have only source-model metadata and use a generated fallback in the browser.
## Fixes made in this pass
- WoW Paladin Illumination (`talent-1461`) now refunds half the selected local Spell.dbc rank's base Mana cost on critical Flash of Light, Holy Light, or Holy Shock, using generated 33/66/100% rank chances. Player and companion casts snapshot the base cost before discounts at cast start. Generated local rank text takes precedence over WotLKDB's conflicting stock 20% proc / 30% refund; the unsupported Light's Hammer cooldown rider remains out because there is no local catalog row. Existing paid-rank semantics are unchanged.
- WoW Paladin Vengeance (`talent-1402`) now applies a 1/2/3% per-stack generated bonus (five stacks, 15 seconds) after positive landed player/companion Paladin critical damage from weapon swings, spells, or abilities. It modifies Holy damage and exact local Crusader Strike/Divine Storm ability rows. Generated tooltip values supersede the conflicting linked child Spell.dbc values (three stacks, 30 seconds, Physical+Holy); periodic events without a critical result and critical heals do not proc.
- WoW Mage Frost Warding (`talent-70`) has two scoped mechanics. The local Mage Fire Ward/Frost Ward proc uses generated 25/50% proc chances, half damage reduction, and a 1:1 Mana refund for player and companion; applying reduction before ordinary Ward absorption is an explicit simulator inference because the generated tooltip leaves ordering unspecified, and stock full-absorb behavior is not imported. Its generated 25/50% Frost Armor/Ice Armor rider scales only positive armor/resistance modifiers on those exact Mage aura effects, for player and companion, while each aura is active. Generic scalar parsing remains guarded; no local Mage Arcane Ward row exists and Shadow Ward remains Warlock-only.
- WoW Hunter Go for the Throat (`talent-1818`) now grants generated 15/30 pet Focus after qualifying player/companion Hunter melee/ranged critical strikes, with a 2-second Hunter-owner cooldown and active living pet Focus cap. The owner-scoped cooldown persisting through pet swaps is an architecture inference. Companion crit setup covers the baseline ranged swing and exact generated direct weapon ability IDs; integration tests exercise the swing and Arcane Shot. Raptor Strike is mapped but not selected by the current Marksmanship AI; traps, Stings, Volley, and unclassified spells are excluded, including a ranged-labeled Explosive Trap. This is a selection coverage limit, not a claim that every mapped strike has an AI-driven event.
- Priest Flash Heal impact is softened for both WoW catalog IDs: scale `0.38`, opacity `0.22`. Cast-start remains unchanged. The original model was inspected and showed a broad, bright impact.
- WoW Mage Arcane Explosion cast-start sphere is tuned to scale `0.65`, opacity `0.5`; the impact cue keeps default tuning after the original purple sphere appeared visually dominant.
- WoW Priest Improved Flash Heal no longer grants its crit talent globally; Inner Focus cooldown reduction now happens when the relevant cast occurs.
- WoW Shaman and Druid Nature's Swiftness now instant-casts the next successful eligible cast-time Nature spell and stays armed until used; Shaman shares its three-minute cooldown with Elemental Mastery. The effect does not grant a haste bonus.
- WoW Shaman Tidal Force now starts with three 20% healing-critical charges; Healing Wave, Lesser Healing Wave, and Chain Heal receive the bonus, and each critical heal spends one charge.
- WoW Shaman Healing Stream Totem ranks 5394–58757 now summon a five-health, nonattacking totem for five minutes. It heals injured party members in 10 yards every two seconds, with each rank's extracted child-spell amount (6–25).
- WoW Death Knight Empower Rune Weapon (47568) now activates all six runes with a single source-aligned effect. Black Ice now treats Frost and Shadow as alternative schools rather than requiring both on one spell.
- WoW Death Knight Anti-Magic Shell now grants 2% Runic Power per point actually absorbed by its live magic-damage shield, respecting the source absorb cap and the Runic Power maximum; damage the shell does not absorb grants none.
- WoW Death Knight Desolation (`talent-2285`) now gives landed Blood Strike hits a self-buff from the local generated child rank: +1/2/3/4/5% damage with all attacks for 20 seconds. Talent rows provide 100% child links 63583/66800/66801/66802/66803 and the generated Blood Strike is spell 45902; no WotLKDB fallback was needed. Local generated data does not define the proc phase, so the landed/main-hand gate is corroborated by the WotLK simulator's [`blood_strike.go`](https://github.com/wowsims/wotlk/blob/master/sim/deathknight/blood_strike.go), not claimed as a primary server-core citation. Player and generated-companion ranks/aura ownership have focused coverage. The current simulator does not emit a distinct off-hand Blood Strike, so only its modeled primary strike can activate the talent.
- WoW Death Knight Blade Barrier (`talent-2017`) reads generated ranks for 1/2/3/4/5% all-damage reduction over 10 seconds and linked child IDs 51789/64855/64856/64858/64859. For players and generated companions, the effect activates when a committed action actually sends a ready base Blood rune into cooldown and leaves both base Blood runes cooling. The hook compares rune slots before and after spending, rather than relying on a Blood cost label: a Death Rune paying Blood cost while both original Blood runes are already cooling does not refresh Blade Barrier. Source data is local generated talent metadata; no WotLKDB fallback was needed. Focused coverage: four helper tests and two player/companion integration tests.
- WoW Rogue Vanish now enters stealth, clears active root/slow control, and leaves the player in place; Preparation resets only Evasion, Sprint, Vanish, Cold Blood, and Shadowstep.
- WoW Warlock Soulshatter (29858) now cuts each nearby enemy's threat by the source-defined 50% in a caster-centered 50-yard radius; targets outside it remain unchanged, including when the area is empty.
- WoW Warlock Death's Grasp now applies its rank 1/2/3% hit bonus to direct player ability attacks and its matching spell haste to spell casts; auto-attacks, periodic ticks, and other classes do not receive the hit bonus.
- WoW Mage Blink now moves forward up to the generated 20-yard distance using the live player-facing yaw, projects to ground, stops before a line-of-sight blocker, and preserves root/stun removal. Its relocation updates the active player position without replacing the run's saved spawn.
- WoW Hunter Readiness preserves Bestial Wrath's cooldown exception. Bestial Wrath requires an active pet and places its source-row 19574 effects on that pet. The Beast Within (34471) now procs only on Bestial Wrath at its generated rank's 50%/100% chance and uses the generated tooltip's six seconds, +15% damage, and -50% mana cost; the populated generated talent entry takes precedence over the conflicting extracted spell row.
- WoW Priest Prayer of Mending ranks 33076/48112/48113 now heal for the extracted base values (800/905/1043), spend one of five damage-taken charges per activation, and transfer to the most injured eligible party member within 40 yards and line of sight. This models five total heals, with up to four transfers; unrelated outgoing damage does not spend a charge.
- WoW Holy Shock retains the player button and both source heal/damage payloads; Death Grip pulls and taunts; Pestilence spreads the caster's two diseases; Chains of Ice keeps its slow without a bogus root; Life Tap and Create Healthstone no longer produce false heals; Swiftmend prefers a caster-owned eligible Rejuvenation/Regrowth or otherwise the shortest remaining one and heals exactly 4/6 ticks. The player can configure Glyph of Swiftmend and preserve that HoT; explicitly configured party Druids can also carry the glyph, while generated companions remain unglyphed.
- WoW Shaman Maelstrom Weapon now receives landed player and companion weapon hits using the attacking hand's own speed. Companion Shamans track equipped main/off-hand autoattacks independently; Stormstrike resolves its generated hand-tagged children and skips an unequipped off-hand, while Lava Lash retains its generated damage and rolls using the off-hand speed. Eligible companion casts reduce cast time by 20% per stack and consume the full bundle only after cast commitment, including instant casts and Lesser Healing Wave support casts.
- WoW Warrior Bloodthirst now keeps player cast/damage fields from 23881 and uses child spell 23880 for three 1%-max-health heals on landed melee hits. Sweeping Strikes selects player self-buff 12328, arms five charges, and applies one hit to the nearest eligible secondary enemy for each landed melee hit.
- RoM Warrior Survival Instinct now checks its health threshold; Moon Cleave runs three hits and checks its two-handed weapon requirement; Shout applies the current [CoA Shout entry](https://chroniclesofarcadia.com/en/wiki/skills/list/1-8)'s 15-Rage, 40-second self-centered area stun without the stale five-target cap (the local RuneWaker snapshot has older values); The Final Battle applies its second hit only below 30% target health; Probing Attack applies a six-second Vulnerable state that Keen Attack requires.
- RoM Knight Shackles of Light resolves its all-enemy root; Knight Smash requires a recent landed player critical hit; RoM Mage Fire Ward applies to the party; RoM Priest support targets are friendly, paired Priest buffs apply to their intended party members, and Priest/Scout Curing Shot (492636) heals every eligible modeled party member and applies six 3-second HoT ticks over 18 seconds; its caster-only +10% Elemental Damage is mapped to the Priest/Scout Water analogue (`frost`), an explicit subclass-based inference.
- RoM Priest/Warlock Prayer of Tribulation (498770) now targets a friendly ally, channels four source-authored heals, and applies its local defense buff using the tooltip's 40% health branches. The local snapshot omits timing, so the matching current [CoA skill entry](https://chroniclesofarcadia.com/en/wiki/skills/list/5-9) supplied only the 1.5-second channel and 5-second cooldown; its newer area-damage and defense-buff payload was not imported.
- RoM Scout/Mage Aggro Transfer now applies its mana regeneration to the selected ally; Scout/Priest Mana Arrows shields up to six nearby allies; Scout/Knight Healing Shot fires its hostile shot and heals the party member with the lowest maximum health.
- RoM Scout, Knight, and Druid ranged skills now enforce their ranged-weapon requirement, including Thorn Arrow, Hidden Peril, Gryphon Bash, Arrow of Vengeance, Healing Arrows, and Unbinding Magic; Warrior/Scout Stun Shot and Scout Neck Strike also enforce it.
- RoM Druid/Mage Spring of Blessings heals nearby party members over time; Druid/Mage Earth Chain chains to three enemies with 70% falloff; Shield of Light applies to up to three nearby allies; Druid/Scout Group Exorcism cleanses nearby allies and consumes its required Nature Power. Knight/Priest Free Will grants its selected ally 10 seconds of Root and Slow immunity.
- RoM Mage/Druid Green Guardian (494331) now follows the exact-pair current CoA active stack skill: player and generated-companion actors gain one stack per full observed stationary second, up to 20, for +1% movement speed per stack. Companion AI uses the zero-cost self skill on its first available combat action when the aura is absent; that selection is a simulator policy. The old Mother Earth's Protection expiry HoTs are suppressed only for Mage-primary/Druid-secondary, and remain available to other local RuneWaker rows. The one-full-stationary-second post-movement reset is a documented timing approximation; CoA does not define pause duration, stack-loss events, or the MP refund basis, so no decay/refund is modeled. See [the source and runtime note](ROM_DRUID_MAGE_GREEN_GUARDIAN.md).
- RoM Warrior/Scout Calm now grants 20 physical hit for 15 seconds only after its paired Skull Breaker fails; landing the attack, failing another ability, and using Warrior without Scout do not trigger it.
- RoM Scout/Warden Thorn Arrow now requires the Briar Shield buff before it can be cast.
- RoM Warden Briar Shield (493642) now applies RuneWaker component 503958's 900-second self aura and +5% armor without dealing damage on cast. A landed physical melee or ranged attack reflects component 503959's level-scaled fraction of main-hand weapon DPS to its attacker within 50 range. The local `runewakerOrgPower(-0.01, characterLevel, 8)` conversion yields 7.4% at level 80 and 9.4% at level 105; no later Chronicles of Arcadia trigger or stat values were imported.
- RoM Warden Crystalline Protection and Acceleration now fan out within the source radius; Coat of Arms applies its source armor/defense buffs to the caster and selected ally.
- RoM Druid/Scout Healing Arrows (494021) now selects its Nature-Power-enhanced HoT when the caster has a point, drains that point, and uses the baseline HoT at zero points. Player and companion casts follow the same branch.
- RoM Plasma Arrow (491168) impact tuning is scale `0.45` and opacity `0.32`; Electric Bolt (491169) is scale `0.6` and opacity `0.45`. These impact adjustments leave cast cues unchanged.
- RoM Warlock/Priest Ring of Comfort heals up to six nearby allies instead of damaging the selected hostile target.
- Champion Rune Pulse 498529 restores five Rage on a landed hit and grants +20% outgoing physical/magical damage for one second at cast acceptance; the bonus expires before its two-second impact. See [the source follow-up](ROM_CHAMPION_SOURCE_FOLLOWUP_2026-10-02.md).
- RoM Champion Kinetic Burn, Vacuum Wave, and Light Pulse resolve their self-centered nearby areas; Shock Strike uses a forward cone; Overrule clears control and grants the stated short control immunity.
- WoW Shaman Maelstrom Weapon applies its generated 2%-per-consumed-stack PvP damage reduction to eligible damage spells, capped at 10% for five stacks. Player and companion instant, cast-time, and channel execution preserve the stack snapshot; only character PvP targets are reduced, while NPC damage and Lesser Healing Wave healing are unchanged. The generated [talent-2057 row](../src/game/wow335Talents.generated.ts#L82504) supplies the rider, so no WotLKDB value was substituted. Focused validation passed 31 tests across the helper, player combat, and companion suites.
### Second-pass class follow-ups
- WoW Priest Test of Faith now applies its rank-scaled healing and Smite/Holy Fire bonus below 50% target health, plus the source-described 10% magic-damage reduction while casting an eligible Priest heal, Smite, or Holy Fire. Divine Aegis, Surge of Light, Serendipity, Shadow Weaving, and Holy Concentration also have event-backed hooks. The focused Priest runtime suite passed 29 tests across three files.
- WoW Priest Focused Will preserves its generated +1/2/3 percentage points of spell critical chance; each landed incoming critical hit grants +3% healing received per stack for 10 seconds, up to three stacks, for player and party Priests. Its conditional healing clause is excluded from unconditional talent modifiers. Player and companion incoming-hit regressions pass.
- WoW Priest Psychic Scream now applies its fear status once per cast, avoiding duplicate boss diminishing-return consumption, and Pain Suppression now remains eligible for low-health mitigation even though it also reduces threat. The Priest AI/control regression suites passed 45 tests across three files.
- WoW Paladin Blessed Life's generated rank tooltips say that all attacks against the Paladin have a 4%/7%/10% chance (ranks 1/2/3) to cause half damage. Player and party enemy-hit paths use stable per-target/per-mob/per-attack/per-revision/per-resolution rolls only after a landed result, after `resolveEnemyDamageResult` and `romWardenWillAttackDamage`, and before mitigation and absorbs. Regressions cover both target paths, rank thresholds, misses, and unrelated party targets.
- WoW Paladin Eye for an Eye reflects the talent rank's 5/10/15% of incoming critical damage, capped at 50% of maximum health. Incoming critical-chance modifiers increase enemy attack crit chance. Divine Sacrifice tracks its source-defined 150%-of-caster-max-health redirect cap. Redemption enforces its out-of-combat gate. Aura Mastery now follows its generated talent tooltip and [WotLKDB's 3.3.5a spell 31821](https://wotlkdb.com/?spell=31821) at six seconds; it reduces represented confuse/fear/sleep duration by 50% on the Paladin, grants silence/interrupt immunity to affected allies, and doubles modeled modifiers from that same Paladin's active aura on each recipient. Its Retribution Aura damage shield uses generated rank base damage as Holy damage and doubles while the matching Aura Mastery is active; player and party incoming-hit paths are covered. Retribution Aura's DBC +0.033 spell-power coefficient now applies to player and companion proc damage. Concentration Aura reduces the existing incoming pushback penalties for player and generated-companion casters using the exact Aura 149 instance and its Paladin source: the generated 35% base plus that source's local Improved Concentration Aura +7/14/20-point rank. Cast delay and channel loss are scaled after spell-specific pushback resistance; the two-hit cap remains, and Aura Mastery does not multiply the reduction. Stock WotLKDB ranks (+5/10/15) are not used. Redoubt follows the generated rank tooltip: shield-equipped block chance is 4/7/10%, each block has a 10% proc chance, and the rank-matched Strength/damage reduction lasts 10 seconds; WotLKDB supplied the missing child duration only. Vindication now uses generated rank chances (17/34/65%) and the local `4.5 × caster level − 3` reduction, with WotLKDB child 67 filling only its missing ten-second duration. Its source-owned debuff reduces the attack-power-derived part of modeled enemy melee damage. Rank 3's capstone AP gain remains unwired: its current DBC has two self-targeted DUMMY effects without an AP operation or child; separate SLS row 209451's child 200067 cannot be borrowed. Focused Paladin tests cover these changes.
- WoW Mage wires Improved Scorch, Fingers of Frost, Hot Streak, and Arcane Concentration from rank-specific data. Clearcasting procs at 5/10/15%, lasts 15 seconds, and makes the next successful active Mage ability free of Mana, Energy, and Rage cost; the missing duration comes from WotLKDB. Interrupted timed casts retain the proc, while channels consume it at their upfront-cost start. Empowered Fire restores 2% of the local level-based Mage base Mana on each positive Ignite tick, capped at the caster's Mana maximum; rank 3 also allows that caster's Living Bomb periodic damage to critically strike. Its generated 7/14/20% rider now increases only the spell-power coefficient of Fireball, Pyroblast, and Living Bomb, leaving DBC base points and die ranges unchanged for player and party Mages.
- RoM Warlock Ruthless Judgment (498544) preserves its RuneWaker damage payload and grants the caster the sourced 20-second, +5% spell-damage aura only when the target is below 20% health. The target does not receive the aura; player and companion casts are covered. Its focused runtime suite passed 12 tests.
- WoW Shaman now wires Ancestral Awakening, Ancestral Healing, Shamanism, rank-scaled Reverberation, Improved Water Shield, Improved Shields, Tidal Waves, and Riptide's target-scoped Chain Heal rider for player and party casters. Improved Water Shield restores the local Water Shield orb mana on qualifying critical Nature heals and doubles its chance for Healing Wave. Tidal Waves uses generated ranks for charges, Healing Wave cast-time reduction, Lesser Healing Wave crit chance, and its 4/8/12% spell-power coefficient; WotLKDB child 53390 fills only the missing 15-second duration. Riptide's 25% Chain Heal boost consumes only the caster's matching HoT on the primary target. Party Shaman heal events now use their actual Nature school for proc checks. Combined Shaman/player/party focused suites passed 54 tests.
- WoW Shaman Elemental Devastation follows generated talent node 1645 for player and party Shamans: a direct Fire, Frost, or Nature spell critical grants 4/8/12% melee and ranged critical chance for 10 seconds. Periodic damage does not trigger it.
- RoM Champion rank 1 Forge installs a five-minute trigger; landed normal melee hits add a capped 8-second, 2%-per-stack attack-power buff and 10 Rage. Its runtime test file passed five tests. Shield Form source learnability is verified, but its toggle/runtime semantics and rank-2 proc chance data remain unavailable; see the focused Champion audit.
- WoW Hunter's Intimidation proc is attributed to the pet and consumes on its successful melee hit. The current player Wolf/Turtle profile and generated-companion Wolf baseline select the highest local Bite rank for pet level, regenerates Focus at five per second, pays Bite's 25 Focus cost, and models Bite as a distinct 1.5-second-GCD special alongside the ordinary swing. Kill Command follows local Spell.dbc rows 34026/34027 and triggered child 58914: +60% pet special damage for 30 seconds, decaying by 20 percentage points on each pet special execution, with a 60-second cooldown. Its 60/40/20% tiers are applied to Bite; autos do not consume them. Mend Pet's HoT targets the living Hunter pet in player and companion casts, companion Hunters cast it below 75% pet health if no HoT is pending, and Revive Pet restores a dead pet at 15% health; companion Hunters automatically revive their dead pet. Furious Howl selects the local level-appropriate Wolf rank and adds its AP/14 × 2-second weapon-speed bonus to pet autoattacks. Pet base health, Strength, AP, and autoattack damage now use local `pet_levelstats` entry 1 and stock TrinityCore 3.3.5 formulas for both player and generated companion pets. Owner stamina and ranged-AP inheritance (45% stamina with +10 health per point; 22% ranged AP to pet AP) now updates dynamically. Pets also inherit spell damage equal to 12.87% of owner ranged AP, and Bite uses local 0.119658 spell-damage and 7% pet-AP coefficients. Other family abilities and utilities remain open. Pet critical inheritance is also unresolved: local pet passive 19591 has zero-valued melee/spell crit aura amounts, and stock 3.3.5 core calculates non-player crit from a 5% base plus pet-owned auras without an owner-crit formula. The only owner-melee-crit formula found is in an unmerged server issue, not stock behavior, so no crit inheritance was added.
- RoM Scout now keeps bow/crossbow accuracy out of melee hit chance, gates Poisonous Spit on Poison Powder, and implements Accurate Targeting's 15-second +50 physical-attack buff with its 30-second cooldown. The ranged-hit consumer and Scout-focused suites passed 49 tests across two files.
- RoM Priest/Mage Lightning Rod (492638) now requires both its passive state and Bone Chill on the target before Lightning applies Electric Shock (20 seconds; −50 Water and Wind resistance). Its focused test file passed three tests.
- RoM Priest/Scout Saint's Blessing (493039) now applies the current CoA +28% damage rider to player and generated-companion packets against living targets below 30% maximum health; direct and periodic damage are checked at each packet. CoA separately lists a Heal rider of +597 and +21% at skill level 105, but the local catalog has no matching Heal 493048 row or lower-rank curve. The older RuneWaker +30/+1%-for-10-seconds Heal aura remains a distinct legacy path and is not evidence for the current CoA rider. See [the source/runtime note](ROM_PRIEST_SCOUT_SAINTS_BLESSING.md).
- RoM Mage rank-2 Catalysis's +50% spell haste now shortens casts/GCDs only for the RoM Mage class; rank 1 and other classes are unchanged. The focused RoM Mage runtime suite passed 10 tests.
- RoM Druid now selects source-backed Nature Power branches for Fountain, Seeds, Wrath, Sandstorm, Earth Chain, Healing Wind, Poisonous Widow, Heart Piercing, and Cross of Thorns, with exact resource drain/refund behavior. Weakening Seed and Withering Seed select their RuneWaker base or empowered modifier component instead of dropping or applying both branches. Holy Fury, Extended Recovery, and Knee Ulcer also use their sourced duration/root values and passive gate. Five focused Druid/RoM suites passed 115 tests; the Seed and caster-resource follow-up passed 86 tests across five files.
- RoM Warden's Will Attack passive now gates Frantic Briar's 10-second, 10% enemy damage reduction and routes it to every affected mob; all modeled incoming melee recipient paths consume the debuff. Tough Oak (494207) also reduces Warden/Mage Punch and Sepal Stab cooldowns by one second each. Briar Shield (493642) applies its sourced 900-second +5% armor aura and reflects local formula 503959's level-scaled main-hand DPS fraction on landed physical melee/ranged attacks within 50 range. Its focused runtime suite passed 15 tests.
- RoM Knight Divine Punishment stores its passive as a marker and applies the extracted 1% bonus only to Punishment damage/DoT components. Knight/Warrior Fearless (490088) preserves RuneWaker's +3% Strength and Stamina auras and grants 20-second Fear immunity; the misleading Fear-control tooltip marker is filtered out. Player and companion regressions passed six tests across two files. Knight/Priest Holy Light's Fury (491635) now reduces Holy Seal cooldown by three seconds; its additional damage rider has no numeric payload. The current CoA patch changes the same skill identity to an 8% healing effect, so local RuneWaker values remain authoritative here. Knight periodic/mechanics suites passed 9 tests in this follow-up. The separate Light-vulnerability component remains unresolved because its extracted resistance direction conflicts with the tooltip.
- WoW Warlock Fel Synergy heals its active pet for 15% of effective spell damage at 50%/100% proc ranks; Soul Leech heals on eligible direct single-target Destruction hits with rank-scaled chance, a 15%-of-damage heal capped at 15% max health, and a 3-second cooldown. It also applies the generated −2 attack-power debuff to the hit target for 10 seconds; modeled enemy melee damage now reduces only its attack-power-derived portion while this aura is active. Eradication procs from Corruption at 15% and grants 7/14/20% cast haste for 10 seconds; Improved Shadow Bolt requires a critical Shadow Bolt and applies a 5% spell-crit vulnerability for 30 seconds. The focused Warlock suite passed 42 tests across four files.
- WoW Warlock Aftermath covers player and generated-companion Warlocks: generated ranks 18119/18120 (companion node `talent-982`) proc at 50%/100% only after a landed direct Conflagrate hit on its primary target, and the generated talent tooltip's custom payload applies a 50% movement slow for four seconds. Companion procs use a deterministic member-seeded roll. The party Conflagrate path derives its burst from that Warlock's active Immolate/Shadowflame DoT and consumes it only after a positive landed hit. This follows the project source preference; the stock [WotLKDB child 18118](https://wotlkdb.com/?spell=18118) instead gives 70% for five seconds. The party regression covers talent ranks 0 and 2, the exact burst amount, and DoT consumption.
- WoW Warlock Metamorphosis now applies the generated 30-second form and its +130% armor contribution, +15% damage, −6 melee critical chance, and −25% stun/snare duration modifiers. It gates Fire/Shadow or shapeshift-safe abilities and adds Shadow Cleave, Challenging Howl, Demon Charge, and Immolation Aura; Immolation uses its local AP-reduction formula. The PvP-only +10% damage rider has no modeled player target. Four focused Warlock suites passed 39 tests.
- WoW Death Knight Butchery now grants 10/20 Runic Power for eligible player killing blows at ranks 1/2, clamps to the resource cap, and ignores ineligible targets and party/pet kills. Its focused runtime test passed 15 cases.
- WoW Mage Impact now uses the active rank-3 row's 4% landed direct-magic-spell proc to arm the next Fire Blast, which stuns for 3 seconds and consumes the charge on a landed cast; a miss preserves it. Impact's 3/6/9% rank damage bonus is scoped to Fire Blast and Meteor, not all Fire spells. The focused Mage/Impact suites passed 14 tests across two files. The local legacy DBC differs on proc chance and stun duration.
- WoW Mage Improved Fire Blast (talent-27) reduces Fire Blast's cooldown by 1/2 seconds and increases its damage against monsters by 5/10% for players and generated companions. Explicit rank modifiers prevent the mixed-unit tooltip parser from inventing values; focused Mage and party tests passed 49 tests across four files.
- WoW Priest Lightwell now maps each summoned rank to its Renew child and applies its source-backed three ticks at two-second intervals over six seconds, including rank-specific base healing and all six coefficients: the first five come from local/AzerothCore rows, while rank 6 uses 62.60% per tick from the exact WotLKDB 3.3.5a entry for child 48085. Its generated rank tooltip's 30%-of-max-health cancellation rule now accumulates effective HP damage separately per recipient and removes that recipient's HoT at threshold; mitigated and absorbed damage do not count. The existing 180-second duration and ten-click limit remain.
- RoM Priest/Warlock Soul Cleansing Ceremony now gates Cleanse's curse-removal category; without the passive, Cleanse remains limited to magic, poison, and disease. Its integration regression verifies that an ally curse is removed with the pair passive.
- WoW Warlock Death's Grasp now gives 1/2/3% hit to direct player ability hits and 1/2/3% spell haste to spell casts; auto-attacks and periodic ticks do not receive the hit bonus.
- WoW Death Knight Anti-Magic Shell now converts actual consumed magic absorb into Runic Power (2% of absorbed damage in the modeled resource scale), respecting shell capacity and resource caps.
- RoM Rogue/Priest Shadow Walker now lets Sneak Attack work in combat, reduces its Energy cost by 10, and adds 10 seconds to its cooldown. The Rogue mechanics and paired-class regression suites passed 60 tests across two files.
- RoM Rogue/Mage Day of Rain (491183) now loses one second of cooldown whenever Throw (490309) is cast and uses a 50% miss chance while Enchanted Throw (491178) is active. Four focused combat/catalog suites passed 110 tests, including cooldown, active-buff tagging, and resolved hit/miss coverage.
- RoM Warrior/Priest Defender's Roar now applies both source-backed maximum-health auras (+300 HP and +1% max HP for 120 seconds) to the caster and party; the separate timeout/proc aura remains caster-only. Its focused runtime test passed 2/2.
- RoM Champion/Warrior Determination Rune (498584) now scales its source-backed shield to 30% of caster max health; other classes and abilities are unchanged. The focused Champion runtime suite passed 7/7.
- RoM Champion Rune Pulse (498529) now restores its source-translated 5 Rage on a landed damage hit instead of granting a cast-duration Rage regeneration aura. Its source component is 622327; Champion runtime tests now cover the effect.
- RoM Mage/Warlock Elemental Extraction (499814) now accepts critical hits from only the RuneWaker-listed triggers 499812 and Electric Explosion (491170); Flame (491150) no longer procs its target defense debuff. Four paired/class suites passed 117 tests.
- RoM Mage Elemental Weakness rank 1 (490247) now applies its sourced 30-second −30 all-resistance debuff to each of the five resistance fields used by combat damage; rank 2 keeps its separate magical-defense effect.
- RoM Mage/Priest Grand Dispel (492928) now makes Mage/Priest Purify remove modeled harmful magic, curse, poison, or disease effects while preserving its one-target cleanse behavior.
- RoM Priest/Warlock Soul Cleansing Ceremony (498771) now lets its pair-scoped passive expand Cleanse (491175) to curses; without the passive, Cleanse remains limited to magic, poison, and disease. Eight Priest/catalog suites passed 119 tests.
- WoW Priest Lightwell now selects the matching Renew child per summoned rank and heals for three ticks at two-second intervals over six seconds, with source-backed per-tick base healing and all six spell-power coefficients; rank-6 child 48085 uses the exact WotLKDB 3.3.5a value of 62.60% per tick. Its generated tooltip's 30%-of-max-health damage cancellation now accumulates effective HP damage per recipient; fully mitigated/absorbed hits do not count. Its existing 180-second duration and ten-click limit remain.
- WoW Warrior's Improved Whirlwind now reduces Whirlwind's cooldown by 1/2 seconds at ranks 1/2 without affecting other attacks. Battle Stance's active 10% armor-penetration aura now applies to physical attacks. Battle Shout and Commanding Shout reach party members within their source 30-yard radius. Improved Heroic Strike and Improved Execute reduce Rage costs by 2/4/6 per rank; Improved Execute damage and Unrelenting Assault damage/cooldown are scoped to the named abilities. Execute keeps its below-20% gate and rank-scaled damage instead of mapping to an instant-kill effect. The focused Warrior runtime, catalog, and talent suites passed 57 tests across three files.
- WoW Druid Improved Rejuvenation parses its rank-scaled +7/14/20% bonus for player healing, and companion Rejuvenation HoTs now snapshot the same owner talent modifier when applied. The focused talent and party runtime suites passed 54 tests across two files.
- WoW Druid Savage Fury now scopes its generated 4/8/12% damage bonus to all six named abilities; its dedicated regression verifies those scopes at all three ranks and excludes unrelated attacks.
- WoW Druid Living Seed now stores 30% of an eligible critical heal at talent ranks' 33/66/100% proc chances, lasts 15 seconds, and blooms on the target's next landed direct hit. The runtime covers the player and party targets; the two tooltip-listed heals absent from the local WoW Druid ability catalog cannot trigger.
- WoW Druid Predatory Instincts (generated `talent-1795`, spells 33859/33866/33867) applies Aura 163's 5/10/15% increase to the bonus portion of critical damage and Aura 229's 4/7/10% reduction against area attacks; the generated “While in Cat Form” scope gates both. Local rank DBC effects provide the values, and [WotLKDB rank 2](https://wotlkdb.com/?spell=33866) confirms Cat Form and both aura types. Player and generated-companion damage paths are covered. The generic `damagePlayer` adapter lacks delivery metadata, so it cannot classify an untagged call as AoE. Predatory Instincts' “does not stack with other similar effects” clause is not independently exercised because no competing AoE-specific reduction is modeled. The focused Predatory Instincts and Master Shapeshifter regressions passed 16 tests across four files.
- Companion resource restores now update only the restored resource pool, preserving the WoW Druid Cat's Energy regeneration when its companion casts Enrage. The party damage audit suite passed 15 tests.
- RoM Warlock Defense Net now retains its 5-second 50% magic mitigation and grants fear, stun, root, and slow immunity to its friendly target; the runtime maps the source's Helpless category to fear because it has no distinct Helpless state. Its focused runtime suite passed seven tests.
- RoM Warlock/Priest Mind Shield now shortens Defense Net to four seconds for that class pair, as its description specifies; the normal spell remains five seconds elsewhere. The Warlock runtime suite passed eight tests.
- WoW Paladin Holy Shield now spends its eight successful-block charges, matching `procCharges=8` on local Spell.dbc ranks 20925, 20927, and 20928. The focused Paladin runtime suite passed 17 tests.
- WoW Mage Flame Throwing adds its generated 2/4/6 yards to hostile damaging-spell range for players and companions; healing range and area-effect radius stay unchanged. The active hostile-cast range paths, including ground targeting, use the bonus.
- WoW Warrior Anger Management grants its generated 2/4/6 Rage every three seconds. Charge grants its local rank's 9/12/15 base Rage plus the talent's 5/10/15 bonus; rank-three Charge also applies the generated 30% damage reduction for four seconds. Charge's generated out-of-combat requirement is enforced for player and companion casts.
- RoM Priest/Warrior Battle Monk Stance lasts the local RuneWaker 900 seconds and gates skills 491362, 491363, 491364, 492635, and 493038. Player casts and companion readiness/target validation require an active, unexpired stance aura.
## Confirmed remaining behavior gaps
These are specific, source-backed gaps that still need implementation or a gameplay test. The catalog contains many more conditional and proc skills than the current focused tests exercise.
### WoW
- **Hunter:** Freezing Arrow, Freezing Trap, Frost Trap, Immolation Trap, and Explosive Trap now have armed-trap runtime behavior for players and companions. Local DBC create-trap rows supply placement lifetime and trigger radius; Freezing Trap uses its local child-spell freeze duration by rank (10/15/20 seconds), and damage breaks the freeze. Companion self-placed traps are recorded at the Hunter's current position and retain their owner and learned rank; Frost Trap uses that owner's Entrapment rank, and Immolation/Explosive Trap damage uses owner level, gear, and talent values captured when the trap triggers. Frost Trap's local aura row supplies a 10-yard, 50% slow zone lasting 30 seconds with a two-second pulse; Entrapment uses generated rank slow bonuses (4/10/15%), local rank proc values (2/4/6%), and its three-second root child. Immolation Trap uses its local child-rank periodic values, five fire ticks every three seconds, and the missing numeric 2% ranged-attack-power-per-tick coefficient from [WotLKDB](https://wotlkdb.com/). Intimidation stores and consumes its next-melee proc on the pet. Beast Within follows the generated rank tooltip (50/100% proc on Bestial Wrath, six-second damage/mana riders) instead of conflicting extracted child amounts. The current Wolf/Turtle player profiles implement the shared level-ranked Bite, Focus cost/regeneration, distinct special and auto attacks, Call/Revive, and Mend Pet targeting; Wolf alone adds Furious Howl. Generated companions remain Wolf, revive their dead pet, and cast Mend Pet below 75% pet health when no HoT is pending. Local Spell.dbc rows 34026/34027 plus triggered child 58914 define Kill Command as +60% pet special-attack damage for 30 seconds, losing 20 percentage points each time a special is executed, with a 60-second cooldown; three Bites therefore use +60/40/20%, while autos leave the aura alone. The base pet table and AP/weapon formulas now match local entry 1 and TrinityCore 3.3.5. Owner stamina/ranged-AP inheritance, 12.87% ranged-AP-to-spell-damage inheritance, and Bite local coefficients of 0.119658 spell damage plus 0.07 pet AP are implemented; broader family abilities/utilities and pet critical inheritance remain unresolved.
- Hunter pet incoming hits now include 35% of the owner's effective armor and 40% of the owner's effective Arcane, Fire, Frost, Nature, and Shadow resistance, added to the pinned level-based pet armor/Agility profile. Player and generated-companion pets use the same shared hit path; pet-owned defense modifiers apply before mitigation, then existing damage-taken auras and absorbs. Holy inheritance remains zero because the character-stat model has no Holy resistance. This formula follows the pinned TrinityCore 3.3.5/TDB server implementation, not direct Blizzard source. Focused coverage passed 11 tests, including an owner armor aura and unchanged non-Hunter summons; see [the source/runtime note](WOW_HUNTER_PET_DEFENSE_INHERITANCE.md).
- Wolf Furious Howl uses the local ranks 24604 and 64491–64495: 20 Focus, a 20-second owner-and-pet AP buff, 40-second recovery, and no pet GCD. Its flat pet AP now contributes `rank AP × 2 / 14` damage to each two-second auto swing, following local stock [`Pet.cpp`](https://github.com/TrinityCore/TrinityCore/blob/3.3.5/src/server/game/Entities/Pet/Pet.cpp) and [`StatSystem.cpp`](https://github.com/TrinityCore/TrinityCore/blob/3.3.5/src/server/game/Entities/Unit/StatSystem.cpp). The same auto-cast and damage path covers player and party companion pets.
- Player Hunter pets now expose Attack/Follow/Stay commands, Defensive/Aggressive/Passive reaction modes, and configurable Growl autocast (off by default). Their target policy consumes an executed owner's hostile-action event, keeps a valid current victim, and respects follow/stay return movement; generated companion Wolves use Follow/Defensive defaults and receive their own owner's action events. Growl selects the local Wolf rank, spends 15 Focus, uses its 5-second category cooldown, and adds the Spell.dbc flat-threat payload to pet-owned threat without a forced-target timer. Player and generated-companion pet regressions cover owner targeting, victim locking, Growl resource/threat behavior, and the absence of a hard taunt. Player Hunters can now select and persist Wolf or Turtle in the active pet frame; Call/Revive retains that choice and family switching is encounter-locked. Generated companions remain Wolf. Turtle uses the existing generic pet base/combat profile plus its source-backed Shell Shield; no new Hunter-specific actor/stat baseline is implied. The extract has 40 family rows, 32 classified as Hunter families, but only the partial Wolf/Turtle profile slice is playable; full family-ability coverage, stable/feed/happiness, training, and pet critical inheritance remain open.
- Bestial Discipline (`talent-1390`) increases the existing 5 Focus/second regeneration for the active tamed Hunter pet by the generated 50%/100% rank, yielding 7.5/10 Focus per second for player and generated-companion Hunters. The existing elapsed-time pool remains continuous because the source specifies a regeneration increase but no discrete tick; the effective rate is stored on the pet pool and remains capped. The separate Intimidation Mana-cost rider stays scoped by the talent modifier parser; companion-controlled Intimidation has a separate coverage limitation in the feature note.
- **Priest:** Desperate Prayer, allied Dispel Magic, party buffs, Pain Suppression threat reduction, Prayer of Mending, Divine Aegis, Surge of Light, Serendipity, Shadow Weaving, Holy Concentration, Test of Faith, Lightwell's rank-specific six-second click heal, and Pain and Suffering have focused runtime behavior. Pain and Suffering uses its generated 33/66/100% proc ranks after Mind Flay, Mind Sear, or Mind Blast and refreshes only the caster's Shadow Word: Pain on that target; the player and companion cast paths preserve the DoT payload. Spell Warding now reduces direct and periodic magic damage by its generated 1/2/3% ranks and leaves physical hits unchanged. Lightwell's generated 30%-of-max-health damage cancellation is implemented per recipient using effective HP damage; its visual remains unreviewed in live gameplay. Rank-6 Renew child 48085 has no local or AzerothCore `spell_bonus_data.sql` row, so its coefficient is sourced directly from [WotLKDB 3.3.5a spell 48085](https://wotlkdb.com/index.php?spell=48085): 62.60% spell power per tick. The 33.33% AzerothCore coefficient belongs to sibling rank 5 child 48084 and was not transferred to rank 6.
- **Death Knight:** Death Coil's friendly Undead heal, Death Strike disease-count self-heal, Anti-Magic Shell and Zone absorbs, Anti-Magic Shell Runic Power from actual absorbed magic damage, Bone Shield charges, Blood Tap rune restriction, Deathchill, Improved Rune Tap, Butchery's eligible-kill Runic Power, Rime's generated 5/10/15% Obliterate proc (Howling Blast cooldown reset and one persistent, one-use rune-free Howling Blast), Mark of Blood's generated 4%-max-health heal on landed damage (20 charges, 20-second duration), Scent of Blood, Sudden Doom, Blood-Caked Blade, and Epidemic have focused behavior/tests. Epidemic adds its local generated 3/6-second duration as one/two extra three-second ticks to Blood Plague and Frost Fever for players and companions. Blood-Caked Blade uses generated 10/20/30% rank chances; the local 50463 child row supplies 25% weapon damage plus 12.5% per active Frost Fever/Blood Plague from that Death Knight on the target. Player main/off-hand autos are separate rolls, companion procs use the companion's rank and disease ownership, and the triggered strike cannot critically hit. Scent of Blood uses generated 15% proc chance after dodge, parry, or direct damage; ranks 1/2/3 grant that many melee-hit charges, each restoring 10 Runic Power. Player and party incoming-event/landed-melee paths are covered, one actual hit consumes only one charge even when the combat event has multiple damage packets, Runic Power respects its cap, and child 50421 expires after 20 seconds. Its trigger rank page [49509 on WotLKDB](https://wotlkdb.com/?spell=49509) shows the 15% proc links but no duration; the missing child duration comes from the matching 3.3.5 [spell 50421 row at WoWRoad](https://wowroad.info/?spell=50421), corroborated by [DVG's 80-level WLK record](https://80.dvg.cn/?spell=50421). Sudden Doom is covered for player and party Death Knights; the triggered player cast preserves the GCD and waives Runic Power, while party effect execution skips a second ability-use commit. Desolation (`talent-2285`) now applies the generated +1/2/3/4/5% all-attack damage aura for 20 seconds after a landed Blood Strike, reading the rank from the player or party actor. Its generated rows supply 100%-chance child links 63583/66800–66803 but omit proc phase, so the landed/main-hand gate is corroborated by the [WotLK simulator handler](https://github.com/wowsims/wotlk/blob/master/sim/deathknight/blood_strike.go); the simulator models one primary Blood Strike and has no separate off-hand event. Hysteria now uses the current Area-52 talent node's +15% physical damage, 1% max-health loss per second, and 30-second duration; the separate class row's +20% damage value is superseded. Dancing Rune Weapon (49028) locally gives 60 Runic Power, instant cast, a 30-yard range, 12-second Rune Weapon and 90-second cooldown; the source-linked child 51906 reduces the weapon's damage by 50%, while the parent 10-point effect is a dummy ([WotLKDB 3.3.5a](https://wotlkdb.com/index.php?spell=49028)). Its 12-second aura now activates for players and generated companions. Both runtimes mirror eligible landed direct hostile primary-target spells and melee autos at half of the owner's pre-target-mitigation raw damage; source gates and 50% scaling have 10 helper tests, with player Death Coil/window-expiry and companion aura/Death Coil/melee integration regressions. The [AzerothCore 3.3.5-derived handler](https://github.com/azerothcore/azerothcore-wotlk/blob/master/src/server/scripts/Spells/spell_dk.cpp#L3260-L3419) supplies the spell-copy/melee-recalculation server reference and its target/utility/AoE restrictions; this is a fork handler, not stock TrinityCore behavior. Because no independent Rune Weapon stats are modeled, mirror damage reuses the owner's raw hit through the existing target damage path; periodic ticks and the separate summon actor are not modeled, and companion use remains a simulator extension. Spell visuals have not received a rendered class pass. Wandering Plague (`talent-2003`) now resolves for player and generated-companion Death Knights on positive Blood Plague/Frost Fever ticks, using the generated 33/66/100% tick-damage ranks and owner melee-critical chance; the one-second owner cooldown is AzerothCore corroboration. The triggered splash cannot recurse and skips active break-on-damage statuses; see [the bounded runtime note](WOW_DEATH_KNIGHT_WANDERING_PLAGUE.md).
- **Death Knight (continued):** Bloody Vengeance (`talent-1944`) reads its 1/2/3% physical damage per stack, three-stack maximum, 15/30/30-second durations, and linked child IDs (50447/50448/50449) from generated talent ranks. It triggers only after a critical hit has dealt positive damage, and applies/refreshes a source-owned physical damage aura after the triggering hit; player and generated companion criticals are supported. Companion autoattacks and generated direct damage abilities get combat-result roll contexts when the talent is learned. Generated channel damage can trigger only when its path emits a critical result; deterministic periodic ticks without a critical result do not trigger it. No external spell database was needed.
- **Rogue:** stealth/dagger gates, five-assault Killing Spree (both weapons per assault), Shadowstep, Riposte readiness, Unfair Advantage's rank 1/2 50/100% main-hand weapon-damage retaliation for player and party Rogues after dodge or parry, with a per-Rogue two-second limit, and future-only Tricks threat routing are covered. Initiative, Ruthlessness, and rank-3 Honor Among Thieves have proc hooks; Honor Among Thieves uses the Rogue's own landed direct-damage casts with a three-second limit. Shadow Walker also enables combat Sneak Attack and applies its sourced cost/cooldown changes only to the Rogue/Priest pair. Combat Potency now runs on distinct off-hand swings: ranks 1/2/3 use the local 33/66/100% chances for 5 Energy, and rank 3 reduces active Blade Flurry and Killing Spree cooldowns by one second per landed off-hand hit. Its custom patch-D child 415010 also explicitly names Combat Readiness (86378) as a one-second recipient, but that ability is absent from the stock 3.3.5 generated catalog. Improved Kick uses the stock two-rank 50%/100% chance to silence for 2 seconds. Its max-rank capstone restores up to 40 Energy and grants 35% attack speed for 6 seconds after a successful interrupt; both effects are modeled for player and party Rogues. The generated movement-speed cap rider is intentionally ignored. Pick Pocket remains excluded from this mechanics pass.
- **Shaman:** Nature's Swiftness, Tidal Force, Healing Stream Totem, Shamanistic Rage, Ancestral Awakening, Ancestral Healing, Shamanism, rank-scaled Reverberation, Maelstrom Weapon, Elemental Oath, Improved Water Shield, Tidal Waves, and Riptide's Chain Heal rider have focused behavior. Convection applies its generated 3/6/9/12/15% mana-cost reduction to modeled Shaman spells through explicit ability scopes. Generated Shaman Convection (talent-564) mentions Earthquake, but local 3.3.5a Spell.dbc has no Earthquake SkillLineAbility assignment and the generated class catalog has no learnable Earthquake row, so no Shaman ability or cost mapping is synthesized. Improved Water Shield restores the rank-scaled Water Shield orb mana on eligible critical Nature heals (double chance for Healing Wave); the generated talent ranks remain authoritative. Improved Shields adds the generated 5/10/15% mana bonus to Water Shield orbs for player and companion Shamans. Tidal Waves grants three Chain Heal or two Riptide charges at the generated rank chance; charges reduce Healing Wave cast time or add Lesser Healing Wave critical chance, and its 4/8/12% spell-power coefficient applies to both heals. Riptide's 25% Chain Heal increase applies only to the caster's matching active Riptide HoT on Chain Heal's primary target, which is then consumed. WotLKDB child 53390 fills only Tidal Waves' missing 15-second duration. Elemental Oath (`talent-2049`) adds its generated 1/2/3 percentage points once to Shaman and party spell-damage and healing critical chance; melee and ranged critical chance are unchanged. Reverberation follows its generated rank tooltip: a successful Shock has the rank's 33/66/100% chance to arm an eight-second, 20% bonus for the next different Shock or Elemental Blast; linked child 965977 is missing, but the generated tooltip contains the implemented mechanic. Elemental Focus (`talent-574`) uses the local generated 50%/100% proc chances and 30% mana discount for the next two Fire/Frost/Nature spells or abilities; after a landed nonperiodic elemental spell critical, the player and generated-companion paths grant two charges that last 15 seconds (local SpellDuration row 8) and consume a charge at cast commitment. The new companion integration matches the existing player rules. Its focused profile and party suites passed 2 and 5 tests. Lightning Overload (`talent-1686`, rank spells 30675/30678/30679) uses [the generated local 3.3.5 rank row](../src/game/wow335Talents.generated.ts#L72628): landed direct Lightning Bolt or Chain Lightning hits use its 7/14/20% chance, tripled on critical hits (21/42/60%). Player and generated-companion paths resolve a same-target echo at half the initiating pre-defense amount, with no extra mana cost or threat; the echo gets its own hit, critical, resistance, and mitigation resolution and cannot recursively proc Overload. Since the local tooltip does not specify per-jump Chain Lightning event rules, the simulator checks each direct target hit in its existing effect loop. Companion Lightning Bolt/Chain Lightning hits now resolve Nature mechanically through `abilityDamageSchool`; the presentation-school field remains unchanged. The separate generated custom Unleashed Storm capstone rider is outside this implementation. Focused helper and player/companion integration validation passed 4 tests. Player and companion Maelstrom Weapon follow the generated eligible-spell list, 20% cast-time reduction per stack, five-stack cap, and whole-bundle next-spell consumption. WotLKDB fills the absent 4/8/12 procs-per-minute rank rates and 30-second duration. Landed player/companion autoattacks and Stormstrike hand strikes use their own weapons' speeds; party tests also cover Lava Lash's off-hand speed and eligible Lesser Healing Wave support casts. Fireball and Frostbolt are Mage spells in the local 3.3.5a catalog: Fireball ranks are assigned to Mage Fire (SkillLine 8, class mask 128) and Frostbolt ranks to Mage Frost (SkillLine 6, class mask 128), with no assignments on Shaman SkillLines 373/374/375 (class mask 64). Their mention in generated Maelstrom Weapon (talent-2057) rank text does not establish Shaman class attribution, so no Shaman rows or gameplay mappings are added. The class-line mapping comes from [the ability generator](../scripts/generate-wow335-abilities.mjs#L16-L23). Its 2%-per-stack PvP damage reduction has no PvP runtime path. Elemental Warding (`talent-1640`, local generated rank spells 28996/28997/28998) reduces owner incoming Fire/Frost/Nature damage by 2/4/6%. Its narrow rank helper ignores the separate Tethered Elemental-only clauses; both player and generated-companion incoming hits apply the school-scoped modifier after existing race/Druid multipliers. The focused 6-test helper/parser suite and 7-test player/companion integration suite pass, covering all three affected schools and unchanged physical/Arcane/Holy/Shadow hits. No Tethered Elemental actor exists, so that pet's 5/10/1Line truncated
- WoW Shaman Flurry (`talent-602`) now grants the actor's generated 4/6/10% melee haste after a landed direct melee critical, for the next three melee autoattack attempts across both hands. Local child Spell.dbc/SpellDuration.dbc rows supply the 15-second aura; WotLKDB's 12/18 child values conflict with the generated expanded tooltips, and rank two's raw basePoints also conflicts with its tooltip's 6%, so the implementation follows the generated tooltip values. Missed swing attempts consume a charge; a critical-triggering swing does not. Re-proc refresh behavior and same-time hand order are explicit assumptions pending stock server evidence. Player and companion integration coverage passed with the helper suite (8 tests); see [the source/runtime note](WOW_SHAMAN_FLURRY.md).
- **Paladin:** Redemption, Reckoning's rank-based proc and three-hit charge window, Eye for an Eye reflection/cap, Divine Storm healing, Beacon transfer, Greater Blessing fanout, Hammer of Wrath health gate, Holy Shield's shield requirement and eight source-defined block charges, Divine Sacrifice redirect cap, aura parsing, Aura Master's 10-second silence and interrupt immunity, Avenger's Shield's three-target/no-falloff chain, Redoubt, and Vindication have targeted fixes or runtime coverage. Redoubt follows generated ranks and requires a shield; its 10% block proc grants rank-scaled Strength and damage reduction. Vindication uses generated 17/34/65% rank chances and the local `4.5 × caster level − 3` attack-power reduction; WotLKDB child 67 supplies only the missing 10-second duration. The source-owned nonstacking debuff reduces the attack-power-derived portion of modeled enemy melee damage. Rank 3's capstone AP gain stays unwired: its current DBC effects are a reducer child plus two self-targeted DUMMY effects with no AP aura or child; the separate SLS row's 200067 link cannot be assigned to rank 3. Aura Master's amplification and active/UI duration/scope discrepancy also remain open.
- **Mage:** Blink root/stun clearing, Improved Scorch, Fingers of Frost, Hot Streak, Arcane Concentration/Clearcasting, Brain Freeze, Missile Barrage, active-row Impact's next-Fire-Blast stun, and Impact's 3/6/9% damage scope on Fire Blast and Meteor have focused coverage. Clearcasting follows generated 5/10/15% proc ranks, spends on the next successful Mage ability, and expires after 15 seconds (duration filled from WotLKDB). Brain Freeze follows its generated trigger ranks and applies a 15-second one-use proc that makes the next Fireball or Frostfire Bolt instant, free of Mana, and 25% stronger; Frozen Orb is absent from the learnable local catalog. Missile Barrage reads per-spell chances from its generated rank descriptions, triggers on landed direct damage from available listed spells or a successfully applied Slow debuff, and makes the next Arcane Missiles channel half as long with half-spaced pulses and no Mana cost; missing child duration comes from WotLKDB's 15-second row. Empowered Fire restores 2% of the caster's local level-based base Mana per positive Ignite tick, respects that caster's Mana cap, and grants rank 3 Living Bomb periodic criticals; its generated 7/14/20% coefficient increase is applied only to Fireball, Pyroblast, and Living Bomb for player and party Mages. Flame Throwing adds the generated 2/4/6 yards to hostile damaging-spell range without expanding healing range or AoE radius. Torment the Weak applies its generated 3/6/9% bonus only to Fireball, Frostbolt, Frostfire Bolt, Pyroblast, Arcane Missiles, Arcane Blast, and Arcane Barrage against a target with an active movement- or attack-speed slow; player and party direct/channel paths are covered. Improved Counterspell applies the generated 4/7/10-second cooldown reduction only to Counterspell and adds its generated two-second silence only after it interrupts an active cast; player and party paths are covered. Frostbite uses its generated 5/10/15% proc chance and four-second freeze for player Frost damage and now also party direct Frost hits and generated Blizzard channel pulses, using actual landed positive damage. Non-player Frost timed/area damage events have an owner-aware hook, but no learnable pure-Frost Mage ground effect currently reaches the area-tick path; no synthetic spell was added. The player path remains on the existing shared damage hook. These mechanics use generated local ranks, so no WotLKDB lookup was needed. Molten Fury suppresses its generic always-on scalar and applies the generated 6%/12% Fire, Frost, or Arcane damage bonus only below 35% target health for player direct/periodic/area damage and party direct/periodic damage; party direct damage includes same-event Sunder bonuses before multiplication, and the threshold is reevaluated per hit or tick. The catalog attribution check is complete: Moonfire and Starfire are Druid ranks (local class skill line 574); Arcane Orb DBC rows 34172/34190 are not mapped to a player class or talent; Frozen Orb and Starsurge have no named row in the local 3.3.5a Spell.dbc. WotLKDB's Frozen Orb 72082 row has no Mage class/trainer attribution, so none of these tooltip references warrants a Mage catalog addition or remap. The active generated Impact row (4% proc, 3-second stun) takes precedence over the legacy DBC row. Focus Magic now takes its recipient +1% spell critical-chance value and tooltip from generated talent node 2211, while its separate +3%/10-second Mage proc remains unchanged; the older enUS ability row 54646 recipient +3% is superseded. Shatter (talent-67) adds generated +17/34/50 percentage points of critical chance to nonperiodic Mage spell hits against frozen targets, including Fingers of Frost, for players and party Mages. Forward Blink movement remains unsupported while player facing is absent.
- **Warlock:** Conflagrate consumption, Shadowflame periodic damage, Seed of Corruption threshold/death explosion, Curse of Agony ramp, Soulshatter, Fel Synergy, Soul Leech healing and its generated 2-AP/10-second target debuff, Eradication, crit-gated Improved Shadow Bolt, Backlash's rank-based proc/cast rider, Death's Grasp's rank-scoped hit/haste effects, Nightfall, Metamorphosis, and RoM Ruthless Judgment's below-20% caster bonus now have focused coverage. The local talent row resolves child 900067's tooltip placeholders to −2 attack power for 10 seconds, although the child spell row itself is absent locally; WotLKDB's exact child URL is inaccessible and has no indexed search result. Its capstone text gives +30% crit after a physical hit while casting, but no generated rank links the unlearnable patch-D helper rows 830297–830299 (a one-charge current-cast buff and cast-finish cleanup); the incoming-hit trigger, rank gate, and consumption behavior remain unestablished, so the rider stays unwired. Nightfall follows its generated rank chances, trigger list, next-ability scope, 25/50% mana discount, 20% Shadow Bolt damage rider, and five-second ICD; its missing 10-second aura duration comes from WotLKDB. Soul Link uses the populated talent tooltip rather than the conflicting dummy DBC row: it shares 6/8/10/12% of post-mitigation incoming damage with a controlled, living, in-range non-Imp demon. The transferred share bypasses absorbs and prevention, and damage beyond the demon's remaining health stays on the caster. Player, enemy-attack, and companion-target paths have tests.
- **Druid:** Eclipse, Omen of Clarity (including successful overheal events), Nature's Grace, Living Seed (33/66/100% rank proc, 30% effective-crit-heal storage, 15-second duration, and bloom on the target's next landed direct hit), Primal Fury's rank-scaled Bear/Dire Bear Rage and Cat combo-point procs, the rank-scaled Improved Rejuvenation healing bonus, Savage Fury's generated 4/8/12% damage increase to Claw, Rake, Shred, Mangle (Cat), Mangle (Bear), and Maul, and Feral Instinct have source-backed behavior. Feral Instinct applies its 10/20/30% damage bonus only to Swipe (Bear), Swipe (Cat), and Ravage; its 1/2/3% Tiger's Fury damage and Enrage damage-taken bonuses are timed to those active buffs, and positive landed damage with Swipe or Ravage reduces both cooldowns by one second. Primal Fury excludes Cat auto-attacks, periodic ticks, and non-combo abilities and caps combo points at five. Living Seed covers modeled player, party, online, and summon recipients. The catalog references were verified: Lesser Healing Wave is a Shaman spell in stock 3.3.5, while Flourish appears only in the custom Ascension class-11 catalog, so neither is missing from the stock Druid catalog. Glyph of Swiftmend is configurable for the player and explicitly configured party Druids; generated companions stay unglyphed by default, and glyph preservation applies only when active. Nature's Reach (talent-764) adds +2/4/6 yards to cast-time/channel damaging spells for players and generated companions; instant damage and healing receive no range bonus. Master Shapeshifter (talent-1915) now applies its generated 2/4% bonus only for the active Bear, Cat, Moonkin, or Tree form, covering player/companion damage and critical chance plus direct/periodic healing paths.
- **Warrior:** Battle Stance armor penetration, Battle/Commanding Shout party radius, Improved Heroic Strike/Execute Rage discounts, Improved Execute's below-20% gate, rank-scaled damage and conditional crit window, Unrelenting Assault's named ability scope, Bloodthirst/Sweeping Strikes, Improved Whirlwind's 1/2-second cooldown reduction, Blood Craze, Second Wind, Anger Management, and Damage Shield have focused behavior tests. Damage Shield reflects the generated 10/20% of the Warrior's resolved block value after a landed direct melee hit, for both players and generated companions. Anger Management grants 2/4/6 Rage per three seconds; Charge gains its 5/10/15 talent bonus atop local rank Rage and rank three applies four seconds of 30% damage reduction. Blood Craze and Second Wind follow their generated rank tooltips for proc triggers and base-health healing, using WotLKDB only for missing periodic cadence details. Unbridled Wrath (`talent-159`) grants the generated 2/4 Rage on landed, damaging main-hand melee autoattacks at the upstream [WotLK Simulator](https://github.com/wowsims/wotlk/blob/master/sim/warrior/talents.go)'s 3 procs-per-minute-per-rank rate, using each Warrior's own un-hasted weapon speed. Player and companion procs are covered; Warrior off-hand autos are not modeled. The generated tooltip takes precedence over the conflicting child payloads (12964/812964). Improved Victory Rush now uses the generated 33/66/100% parry chances, 10-second window, 12-second internal cooldown, +20/40/60 percentage points of critical chance, and +33/66/100% threat while using the parry window; base Victory Rush also opens for 20 seconds after an XP-yielding kill. Player and generated companion casts require and consume readiness. Critical Block (`talent-1893`) applies its generated 8/16/25% additional reduction to successful blocks for players and generated companions, except against player attackers and with Touched by the Light (`talent-2195`); the conflicting stock double-block chance is not used. Improved Defensive Stance applies its generated stance mitigation and avoidance-triggered Enrage proc for both paths.
### RoM
- **Warrior:** Survival thresholds, weapon requirements, three-hit Moon Cleave, several Slash/state riders, and Warrior/Priest Defender's Roar party max-health effects have focused fixes. Warrior/Scout Calm now adds +20 physical hit for 15 seconds after failed Skull Breaker, following the populated RuneWaker passive/component values. Druid/Warrior Briar Technique now gains up to five +3% Physical Attack/+3% Wisdom stacks for 15 seconds on landed Natural Attack or Heart Piercing hits while its passive is learned; the local child payload is duplicated on those two skills, so the implementation scopes the proc to those source-backed triggers. The [current CoA Druid/Warrior page](https://chroniclesofarcadia.com/en/wiki/skills/list/8-1) names Cross Thorn Blow (494018) as a third trigger, but the matching RuneWaker ability row is absent; its locally referenced child 499956 is also missing, so no third trigger has been inferred. The current CoA [Warrior/Knight page](https://chroniclesofarcadia.com/wiki/skills/list/1-6?locale=en) identifies local Heroic Surprise Attack (492661) as Heroic Charge Attack. It keeps Resist at 493251 and lists the distinct level-50 Blocking Stance upgrade at 493287; current CoA says Resist grants +80% Aggro and +20% received physical-damage reduction while that stance is active. Patch 11.1.1 introduced the aggro effect (current value supersedes the older +75.6% patch text), and patch 12.1.3 says the missing damage-reduction effect was fixed. Blocking Stance and Resist are now cataloged and integrated separately for player and generated-companion incoming hits and threat, gated by each learned passive plus active local Blocking Stance 491480. Blocking supplies +8% Parry, −18.9% damage taken, and +75.4% Aggro; Resist supplies +80% Aggro and −20% physical damage taken. The two Aggro factors remain individually modeled but their overlap is neutral/unmodeled until a stacking rule is sourced. The 3-Rage proc and 10-second lockout are retained as tooltip information only because the proc chance is unspecified. Recovery of Life (494377) has a pair/learned-passive-gated runtime helper for current CoA Rage of Calmness: local RuneWaker values provide −10 Rage and −10 seconds to modeled Whirlwind 490133, applied for both player casts and generated companions. Component 506368 supplies the 20-second post-hit window. CoA confirms the effect directions but points to Whirlwind 494939; the ID mismatch is documented. Its general post-hit Rage reduction stays unwired because neither source quantifies it. The Warrior/Druid Whirlwind row separately lists a 30% reduction for 15 seconds with a 20-second retrigger lockout, but it does not explicitly link that rider to passive 494377; do not transfer those values. See [the bounded source audit](ROM_WARRIOR_RAGE_OF_CALMNESS_SOURCE_AUDIT.md). Source: [CoA Warrior/Druid page](https://chroniclesofarcadia.com/en/wiki/skills/list/1-8). Current CoA [Warrior/Rogue](https://chroniclesofarcadia.com/en/wiki/skills/list/1-3) confirms Exhaustion's (493248) identity and passive Whirlwind reductions. The runtime now restores 25 Energy and 50 Rage with a deterministic 30% chance after landed pair Probing Attack 493283, only when Exhaustion is learned; player cast-path coverage and a capped generated-companion hook regression are included. Its separate catalog row uses 664.3% main-hand weapon DPS, or 1116.9% with caster-owned Bleed or the locally represented two-handed mace/hammer. The unspecified hammer cooldown rider is not modeled. Local primary-Warrior Probing Attack 491133 remains distinct. The earlier audit claim that 493248 was Morale Slash and 493283 Exhaustion was incorrect: the current page lists 493248 as Exhaustion and Morale Slash as 1491760. The [Warrior/Warlock page](https://chroniclesofarcadia.com/en/wiki/skills/list/1-9) describes Speed Slash (499827) as increasing Slash damage and reducing its Rage cost by 10, and Excellent Combat Training (499806) as +20% Physical Damage. Runtime already models the known −10 Rage cost and +20% Physical Damage; it leaves Speed Slash's unquantified damage increase and RuneWaker's unsupported cooldown-reset references alone. Generated tooltips now state the supported −10 Rage and +20% Physical Damage effects without restoring the unsupported cooldown resets.
- **Scout:** Ranged Weapon Mastery's bow/crossbow accuracy now affects ranged hit chance only; Poisonous Spit uses its landed-hit triggers and RuneWaker item 200563 Poison Powder as an unlimited carried reagent, without the separate Rogue Poison Bottle aura; Accurate Targeting grants its source-backed buff and cooldown; and Scout/Priest Sniper reduces Snipe's cast time by one second. Scout/Warrior Enhanced Throat Attack and Rogue/Scout Slit Throat now silence a target for four seconds after a landed Throat Attack. Hash-matched local RuneWaker rows do not quantify Enhanced Throat Attack's extra range or link a range modifier to Throat Attack; the passive's own range field 5 is cast-distance metadata, not an additive range bonus. The [current CoA Scout skills page](https://chroniclesofarcadia.com/wiki/skills/list/2-6?locale=en) confirms ranged-weapon requirements for Shot, Joint Blow, Vampire Arrows, Wind Arrows, and Autoshot; the combat validator now enforces those requirements, with player and companion rejection covered for Scout secondary skills without a ranged slot. Current CoA Drums of War (493010) replaces RuneWaker's +20 physical/magical critical-strike rating payload: after a landed local ranged Shot 490423 (the CoA same-name/role Shot is 493011), it grants +20% critical damage for 15 seconds to the living party within modeled range 50. Another 15-second post-expiry lockout makes the next proc ready 30 seconds after activation. The shared player/companion critical resolver adds this to the critical bonus portion, preserving crit chance and ordinary hits; it adds with the Warlock/Priest +25% critical bonus for party actors that have both auras. Current CoA Screen Attack (499555) replaces the local passive marker with an active 17.4% damage buff for 20 seconds and a 60-second cooldown. The current skill page's +55 is skill training, so the simulator applies the max-row value at all character levels. Its radius 150 is modeled as 15 project units; recipients follow the existing living-party, 3D-radius, and line-of-sight checks. Patch 11.1.1 states 30 seconds, but the current CoA skill row states 20; runtime follows the current row and uses the patch only for periodic-damage coverage. Player and generated-companion tests cover activation, recipients, direct/periodic damage, expiry, and cooldown. Priest/Scout Curing Shot (492636) now uses the current CoA instant cast, 6-second cooldown, +105 heal values, uncapped modeled-party fan-out, and caster-only +10% subclass-defined Elemental Damage. The Priest/Scout kit is water-themed, so the simulator maps this buff to its `frost` Water analogue only; fire/nature/arcane/holy/shadow/physical remain unchanged. Its 120 MP local cost is preserved because no lower-rank CoA cost is published. See [the source/runtime note](ROM_PRIEST_SCOUT_CURING_SHOT.md). The generic damage resolver now filters expired dealt-damage auras at the timestamp boundary, which makes timed party buffs stop affecting the exact expiry-time hit. RuneWaker pet crit/dodge/damage passives remain unsupported because its non-Hunter summons lack the needed pet-specific stats or event path; this does not describe the separate WoW Hunter pet model. Other paired passives still need review.
- Scout/Knight Enhanced Armor Perfection (492346) sets Enhanced Armor's duration to the 600 seconds stated by local component 501823. Scout/Priest Sniper (492344) now reduces Snipe's cast by one second for both players and generated party Scouts. Wind Return (499548), Revival Engraving (499552), and Forest Guidance (499575) are exact-pair learned markers only: their translated child effects no longer appear on the passive owner, while missing trigger rows and unsupported companion targeting remain open. See [the source audit](ROM_SCOUT_REMAINING_PASSIVES_AUDIT.md).
- **Rogue:** Dagger Mastery, Treasure Hunter, Weakened Soul Stab, rear-position gates, Sneak Attack's out-of-combat gate, resource gates, Rogue/Priest Shadow Walker, and Rogue/Mage Day of Rain's Throw cooldown and Enchanted Throw hit-rate interaction have targeted behavior. Rogue/Priest Sinister Methods now grants +20 physical critical strike for 10 seconds on landed Low Blow or Blind Spot hits, including critical hits, with a 20-second cooldown; the passive is only a marker until one of those hits lands. Instant Shadow (497206) now arms after a successful dodge and can be activated for the local child 502597's three-second stealth. Enchanted Throw (491178) links its buff component 501279 to hidden physical child 491185, also described by passive 491184. Child component 502595 combines skill-scaled main-hand DPS and `Throw_DMG`; component 502596 grants 10% physical and magic damage reduction for four seconds. RuneWaker C++ source defines these terms, but Healer Man does not have the native `Main_DMG`/`Throw_DMG` derivation or `CalPhyDamage` mitigation inputs. Player and companion incoming-hit branches are present in `combatStore.ts`; no child counterattack hook has been added. The mechanic remains unresolved, and the existing player outgoing Throw (490309) fallback stays in place. Projectile ammunition is not modeled. Off Hand Mastery (490143) now applies RuneWaker component 620335's +4% off-hand damage and +4 percentage-point accuracy modifiers to player and companion off-hand swings. RoM Rogue autoattacks use separate hand timing; companion main-hand hits also use the dual-wield hit table when an off-hand weapon is equipped. Focused regressions cover player and party swing behavior. The [current CoA Rogue page](https://chroniclesofarcadia.com/en/wiki/skills/list/3-1) reports later level-55 values that were not copied into the RuneWaker model.
- RuneWaker Numbing Dagger (490347) supplies a 10-second creature sleep (500737) and a separate 3-second player sleep (503046). `applyStatus` now selects the local duration by defender kind for player casts, companion casts, and the lower-level control action; focused regressions cover NPC and character-defender targets.
- Rogue/Scout Coerce (493019) now follows the current [CoA skill entry](https://chroniclesofarcadia.com/en/wiki/skills/list/3-2): Low Blow deals 20.2% more damage and costs 5 fewer Energy. The Wiki says “lesser energy cost” without a number, so the implementation keeps only the compatible −5 amount in the RuneWaker tooltip; it removes RuneWaker's below-30%-health temporary +2% Physical Damage proc because CoA defines a different direct Low Blow modifier. Both player and generated-companion casts are covered. Focused Rogue mechanic, pair validation, and party ability tests passed (98 total); the TypeScript no-emit check passed.
- **Rogue/Champion Nerve Gear:** RuneWaker passive 498839 (child 621652) now remains a learned marker; each successful non-passive Rogue/Champion elite-skill cast grants +5% attack speed and +2 dodge for 5 seconds, stacking to five. Player and party hooks apply once per cast, including area casts.
- **Rogue Poison:** RuneWaker Poison (490329) component 500715 specifies a 50% normal-attack trigger to child 490357. Its local tooltip supplies a four-stack cap and a 2% reduction to target damage per stack. Player and party landed normal attacks now apply source-owned stacks when that Rogue has learned Poison and its self aura is active; the common enemy-hit consumer applies the debuff to melee, ranged, and spell damage. The hidden child has no local duration row, so only its missing 900-second duration is taken from the [current CoA Rogue skills page](https://chroniclesofarcadia.com/en/wiki/skills/list/3-1); its conflicting 8% reduction and attack-speed rider are excluded.
- **Priest:** Knight/Priest Holy Smite now heals and consumes Holy Seals correctly; Holy Protection applies its alternate threat payload as intended; Priest/Knight Holy Power applies RuneWaker's +60 Wisdom and +1% Wisdom for 20 seconds, ending after three successful casts of Heal; Priest/Mage Enlightenment (492933) follows current CoA as a permanent +12% Wisdom passive for the same Priest/Mage pair, replacing RuneWaker’s completed-Heal (490261) +1% Wisdom for 8 seconds and its 20-second internal cooldown; the catalog tooltip matches CoA, and the player passive synchronizer applies the permanent aura on build initialization/update while generated companions apply the learned self-passive before their first RuneWaker cast. Lightning Rod requires the sourced Bone Chill target state; Priest/Scout Saint's Blessing applies current CoA's +28% damage below 30% maximum target HP, while its separate +597/+21% Heal rider at skill level 105 remains unresolved because the local Heal row and lower-rank curve are absent; Priest/Warrior Battle Monk Stance gates five stance-dependent abilities for player and companion paths; Priest/Warlock Prayer of Tribulation has focused runtime coverage; and Soul Cleansing Ceremony conditionally extends Cleanse to curses. Blessed Spring Water (490298), Embrace of the Water Spirit (491323), and Shadow Fury (492932) now apply their source-described modifier auras to the party; Embrace's separate periodic proc remains caster-only. Current CoA reworks Infused Light Chain (498610) into Rage Control: +20 Rage per completed second of channeling. Player and generated-companion completion and interruption paths now grant only whole elapsed channel seconds; ordinary casts do not count, replacing the unsupported local Chain of Light damage, cooldown, and on-hit riders. Protection Rune Seal (498613) attaches a hidden monitor to Regenerate and uses the local 8% chance to reset Heart Rune Energy on a successful periodic tick, including the final tick before expiry. Its local generated passive row has no components or heal scalar, and current CoA describes only a “slight chance” to reset Heart Rune Energy; neither source establishes the local tooltip's increased-healing clause or quantifies it, so it remains unwired rather than inferred from the reset chance. Beacon of Regeneration (498620) now applies the current CoA 30-second effect to one friendly marked member, once per direct healing cast after recipients are aggregated. The CoA +105 row publishes 770 HP; because skill progression is unavailable, every unlocked rank uses that documented value. Player and companion casts both apply generic source healing-done and recipient healing-taken modifiers (raw 770, Faith +5% = 809 on either path). The local range 20 is decimeters and matches CoA range 200; its level-50 29 flat MP cost differs from the CoA +105 88 flat MP, with no supported cost curve. Child 621227 does not map to the current trigger or amount. HoT ticks and channel pulses remain outside the event model because structured healing events lack a periodic marker and CoA does not settle their eligibility. Protection Rune Seal (498613) now resets the exact actor's learned Heart Rune Energy only on a positive periodic Regenerate (490269) heal, for both player and generated companion owners. The local 8% chance remains because current CoA only says “slight chance”; the possible healing-strength rider has no sourced value and remains open. See [the focused audit](ROM_PRIEST_REMAINING_PASSIVES_AUDIT.md). The 10.2.1 patch explicitly renames local Ice Fog ranks 1/2/3 (490274/490275/490276) to Holy Blessing, Vow of Silence, and Holy Void, respectively; the [current Priest skill list](https://chroniclesofarcadia.com/wiki/skills/list/5-1) confirms each ID and level. This is a patch-backed identity mapping, not an ID-only inference; Bone Chill is separate ID 491165. Holy Blessing (490274) follows the current [CoA Priest-primary entry](https://chroniclesofarcadia.com/en/wiki/skills/list/5-7): its permanent `(current Wisdom + 115) × 1.105` Wisdom formula and +100.9% Light damage are represented by a tagged caster aura. Existing Wisdom modifiers resolve first; only the incremental Wisdom-to-spell-power conversion is injected into coefficient-based spell amounts, because cast scaling bypasses `applyAuraStats`, and generic spell-power aura fields are not double-counted. Light maps to Holy; the player source aura is school-scoped, and generated-companion direct spell damage applies the same tagged modifier on the deterministic party path. CoA does not specify stacking with other Wisdom buffs, so existing stat-resolver behavior is retained before Holy Blessing. Two player/companion combat regressions verify actual spell amounts and Holy-versus-Nature damage; the four-file focused Priest suite passes 14 tests. The player Frost control includes RuneWaker's existing “Prayer: water-damage” +5% Frost aura when predicting the actual event amount. Vow ofLine truncated
- **Priest/Champion Heart Rune Energy (498612):** current CoA keeps the same name, ID, and pair but deliberately replaces the local RuneWaker heal/Mind buff with 975.1% CPS Light damage (runtime coefficient 9.751, Holy school), 15 Rage cost, 150 range, an 80-radius caster-centered AoE, instant cast, and 12-second cooldown. Patch [11.1.5.3000](https://chroniclesofarcadia.com/tr/patch/11-1-5-3000) confirms the damage rework and a 15-second Blessing of Humility cooldown reduction on use; patch [11.1.5.4002](https://chroniclesofarcadia.com/patch/11-1-5-4000) confirms the AoE is centered on the caster with 80 range. Player and generated-companion execution has focused coverage for the Rage cost, Holy-school damage to all six in-radius test targets, exclusion of a target just outside the radius, 12-second cooldown, and Blessing cooldown reduction. CoA and the catalog provide no target-count cap, so runtime leaves it uncapped rather than guessing; party target resolution covers modeled visible/engaged mobs. Protection Rune Seal (498613) now handles player and generated-companion Regenerate (490269) positive periodic heals under the exact learned Priest/Champion passive and actor-owned aura. The local 8% chance remains because CoA says only “slight chance”; each success resets only that actor's learned Heart Rune Energy (498612) cooldown, with companion cooldown state synchronized. The separate possible heal-strength rider remains unsourced; see [the source audit](ROM_PRIEST_REMAINING_PASSIVES_AUDIT.md).
- **Knight/Warrior CoA batch:** current CoA removes the periodic-damage component from Holy Seal and converts Knight-primary Holy Power Explosion (490172) from its local active mana/healing effect to a passive +198% Aggro modifier. Patch [10.6.1](https://chroniclesofarcadia.com/en/patch/10-6-1-1000) supplies the Holy Seal change; patch [12.1.3](https://chroniclesofarcadia.com/patch/12-1-3-1000) confirms Holy Power Explosion's current value. The generated local Holy Power Explosion row is `rom-knight`, so its threat effect belongs on Knight actions, not Warrior-primary actions. The current CoA pair page has a level-50 Warrior/Knight Blocking Stance passive (493287), now represented as a separate catalog marker from Resist (493251) and local active Blocking Stance (491480). Its +8% parry, −18.9% received damage, and +75.4% Aggro are modeled as separate helper modifiers from Resist's +80% Aggro/20% physical reduction; each requires its passive plus the separate active stance, and they are not combined until the source/runtime stacking rule is established. Player and companion runtime integration now removes only the four legacy Holy Seal DoTs, applies Knight-only Holy Power Explosion +198% Aggro, and gates Blocking Stance/Resist mitigation on the learned passives plus active stance. Separate helper, catalog, combat, and runtime regressions cover the effects; the two Rage proc chances remain unresolved. Leopard Instinct (495402) now updates hit stacks and Dodge-stack loss for player and generated-companion incoming-hit paths. Each stack grants +3 percentage points Dodge; its separate Magic Resistance Rate value is retained in helper state but remains unapplied because the stat model has no consumer.
- **Knight/Rogue Leopard Instinct (495402):** current CoA describes a passive: each received hit adds a stack of +3% Dodge and +3% Magic Resistance Rate, up to 10; a dodge removes one stack. Patch [11.1.5.3000](https://chroniclesofarcadia.com/tr/patch/11-1-5-3000) replaced the three-hit absorb with this stack behavior, and patch [12.1.2](https://chroniclesofarcadia.com/fr/patch/12-1-2-1000) made the skill passive. The current source says each hit, not specifically a normal attack; player and generated-companion hit paths increment its persistent stack aura, and each dodge removes one stack. There is no duration, cooldown, or absorb in the current version; the 20-second/90-second values are historical. Each stack grants +3 percentage points Dodge. The separate Magic Resistance Rate component is intentionally unapplied because the simulator has no stat consumer; it is not folded into spell resistance or another unrelated stat.
- **Priest/Warrior Condensed Rage (493038):** the current [CoA Priest/Warrior entry](https://chroniclesofarcadia.com/en/wiki/skills/list/5-1) confirms the same name, ID, and class pair, with a +22% Physical Damage passive. Patch [11.1.1](https://chroniclesofarcadia.com/patch/11-1-1-3000) changed the rider from Water/Light Damage to Physical Damage; patch [11.1.1.5000](https://chroniclesofarcadia.com/patch/11-1-1-5000) removed the buff requirement. This supersedes RuneWaker's incoming-hit healing description and missing-child references 493056/495293. The generated catalog/tooltip and player/companion physical-damage paths now use the learned passive without a trigger or stance gate; focused regressions cover both actor paths.
- **Priest/Champion Rage Control (498610):** current CoA keeps the same ID and pair but reworks RuneWaker's Infused Light Chain into a passive that grants 20 Rage for each completed second of spell channeling, per the [current CoA Priest/Champion list](https://chroniclesofarcadia.com/en/wiki/skills/list/5-10). This replaces the local unsupported Chain of Light damage, cooldown, and on-hit Rage riders. Player/party channel completion and interruption paths grant only whole elapsed channel seconds; ordinary casts and partial seconds do not count. The generated tooltip reflects the new passive. The source does not specify additional channel exceptions.
- **Knight:** Divine Punishment now follows current CoA's +28.5% Punishment damage and applies a 10-second general damage-taken increase of 2% per pre-spend Holy Seal stack, replacing the RuneWaker +1% Light-only modifier. Deadly Whirlwind retains the local RuneWaker −10 Rage/−20-second Warrior Whirlwind adjustments because current CoA still says the passive reduces its Rage cost and cooldown but does not publish amounts. On successful Whirlwind hits it adds CoA Deadly Wound: −30% healing received for 10 seconds on NPCs or 5 seconds on player targets. Compassion of Holy Light (491635) is a documented cross-pair bridge: the selected English CoA [skill list](https://chroniclesofarcadia.com/wiki/skills/list/6-5?locale=en) reports Knight/Shaman, while localized/index results disagree on the displayed pair. This simulator has no playable Shaman class/pair, so the local Knight/Priest row stays and uses the explicit CoA payload; it does not assert that the pair identities match. The [11.1.5 patch](https://chroniclesofarcadia.com/patch/11-1-5-3000) supplies the 120 + 0.2 × STA landed-hit heal, Holy Illumination trigger, and 5-to-4-second cooldown reduction; player and generated companion casts are covered. Holy Illumination supplies 15% damage reduction for 10 seconds. The simulator has no shield-defense stat, so the patch's 5× shield-defense damage rider is not represented. Focused validation passed 22 tests across the Knight override, periodic runtime, and Whirlwind integration files; the narrow TypeScript check passed. Disregard Danger (493273) still redirects 40% of one ally hit for 10 seconds, consumes the redirect after the first hit, and gives the caster +20 Parry for 10 seconds; its integration test verifies the 40/60 split and that the next hit is unredirected. Master of Parry (492935) applies the generated +5,000 Parry modifier for 15 seconds and consumes it after two successful blocks; its hidden periodic trigger shares the source 15-second lifetime. Shield of Valor (490468) reduces a party Knight's Holy Seal cooldown by 1 second on each parry while its local 15-second aura is active. War Prayer (490078) schedules six personal Holy Seal increments at 3-second intervals over 18 seconds; local child 490079 is absent, but the current CoA [skill entry](https://chroniclesofarcadia.com/en/wiki/skills/list/6-1) and [fix patch](https://chroniclesofarcadia.com/patch/10-4-1-1000) corroborate the personal Seal mechanic. God's Sword (491621) is a continuous same-ID/name/pair rework: CoA 10.6.1 changed it to offhand-DPS Light damage, 11.1.5 set the coefficient to 350%, and 12.1.0 made it passive. The current [CoA Knight/Rogue entry](https://chroniclesofarcadia.com/wiki/skills/list/6-3?locale=ru) says offensive physical abilities add 350% offhand weapon DPS as Light damage with high Aggro, superseding RuneWaker's +40% Holy Strike crit rider. Player and generated Knight/Rogue companion runtime integration now records a separate Light/Holy damage packet at 3.5× offhand DPS after a qualifying landed direct physical hit, gated by the learned passive, exact pairing, and positive offhand DPS. Four helper tests and three integration tests cover those gates and actor paths. CoA does not publish an Aggro multiplier or multi-hit, channel, or AoE cadence, so none is inferred. Holy Light's Fury's extra damage value and remaining periodic/triggered spell references are unresolved. Throw Shield and Shield Bash require an equipped shield; Arrow of Vengeance enforces its ranged-weapon requirement. Knight/Rogue Panther's Blessing (493047) now follows the current CoA same-name, same-pair passive: a resolved incoming dodge restores 10% max HP and 1% max MP. Max-pool basis and whole-point rounding are simulator interpretations because CoA does not specify either; the legacy RuneWaker +2 Dodge child is suppressed. It is distinct from God's Vengeance 499934. See [the runtime note](ROM_KNIGHT_PANTHER_DODGE_PROC_2026-10-02.md).
- **Warden:** Nature Crystal immunity, Heart of Oak/Crystalline absorbs, Awakened immunity/next-crit behavior, Nature Power scaling for Healing Ripple/Gift Pulse, Spirit of Life party HoT, Mysterious Grace party scope, Will Attack's Frantic Briar debuff, Damage Transfer's 30% split to a live nearby pet, Tough Oak's one-second Punch/Sepal Stab cooldown reductions, and Briar Shield's sourced 900-second +5% armor aura plus level-scaled physical reflection have focused fixes. Briar Shield uses RuneWaker's local formula for main-hand DPS reflection on landed physical melee/ranged attacks within 50 range; newer Wiki trigger/stat behavior was not imported. Tough Oak's pet-defense rider has no pet-stat model; local RuneWaker encodes +5% armor while current CoA specifies +60% pet Physical Defense, so no proxy value was added. Oak Blessing (494011) now activates RuneWaker component 620679's +5% physical attack aura and 1%-maximum-HP healing every three seconds only during Heart of the Oak's 60-second duration. The hash-matched RuneWaker source contains Damage Transfer child 493416 and Lua `01460.lua`; executable component 503942 transfers 30% for 10 seconds when the owner's supported pet (102297/102324/102325) is alive within inclusive 3D range 300. Player and generated-party incoming-hit paths apply the split once and sync pet health/absorbs; party coverage checks the 30/70 split, range and expiry, and a single pet event. Tooltip component 503643's 15-second value is not executable. The [current CoA Warden page](https://chroniclesofarcadia.com/en/wiki/skills/list/7-2) does not resolve the RuneWaker conflict. Revival (499542) now uses the source-proven self-heal `maxHP × (10 + 5 × charges)%`, with normal/noncritical FixPer and no weapon, attack-speed, MagicPow, or critical-power scaling. The supplemental learned 499544 row arms its 900-second state; exact-pair player and generated-companion paths add their own 15-second/max-10 charges only after normal post-absorb HP damage that leaves the actor alive, and apply the sourced six-second +20 physical-dodge-rate aura. The separate 620302 HolyHeal and type-200 magical-dodge channel remain unavailable because the simulator lacks native MND/MPow/heal-rate and magical-dodge consumers. Direct `damagePlayer` coverage is an explicit positive post-absorb/normal-hit adapter approximation because that API has no outcome metadata. Current CoA reuses ID 499542 for Rogue/Warden Low Blow, a different skill; it is not mapped onto local Revival. Weak Point Strike (494043) still has sourced base/bonus-hit formulas but no proc chance; current CoA reuses the ID for Blood Hound, so no proc or identity is inferred. See [the state-chain source audit](ROM_WARDEN_REVIVAL_STATE_AUDIT.md) and [the remaining mechanics audit](ROM_WARDEN_REMAINING_MECHANICS_AUDIT.md). Other reactive passives remain incomplete.
- **Mage:** rank-1 Catalysis mana ticks, rank-2 Catalysis cast haste, Phoenix's 12-target cap, Control Flame and rank-1 Elemental Weakness's all-resistance debuff are covered. Flame Follower 494051 remains source-blocked for its Fireball cooldown/critical-rate rider. Elemental Extraction's critical triggers now match its RuneWaker tooltip. Meditative Current now suppresses the generic always-on passive payload and applies its source-complete rule (landed Flame 491150 or Plasma Arrow 491169, +10 spell haste for 10 seconds, 30-second internal cooldown) to player and party Mage casters, with an independent cooldown marker per caster and focused runtime coverage. Mage/Knight Light of Day (493034) now suppresses its generic passive aura and grants +8% Holy damage for 15 seconds only after a landed direct Holy Light Strike (491594) or Light Charge (492634) hit, with an independent 20-second cooldown per caster; player and party regressions cover both triggers, startup suppression, and cooldown behavior. Fireball 490204 is intentionally excluded by the local tooltip. Eruption's local passive row (490221) has no proc chance or effect payload. Hash-matched RuneWaker MagicObject trigger fields contain no edge to Eruption; Fireball (490204) and Flame (491150) likewise do not link the passive. Party Mage casts now receive the same deterministic 30% base proc roll as player casts. The existing damage-doubling formula remains unchanged and unverified: no source defines the baseline for the “200%” damage statement. The current CoA entry has the same name, ID, and Mage-primary pairing and confirms Fireball/Flame triggers, so CoA patch 10.2.1 supplies the selected 30% base proc chance (up from 10%). Patch 12.1.0.5000 implies Elemental Catalysis also raises Eruption's chance but gives no value, so that bonus remains unapplied. Patch 10.2.1.1250 raised Eruption damage to 200% without defining its baseline; do not interpret that as either an extra 200% hit or a 2x total multiplier. The sourced base chance is being applied while the damage payload remains unresolved. Rank 2's source payload has no mana tick. Flame Follower 494051 remains unresolved: its local tooltip lists a one-second Fireball cooldown reduction and increased critical rate, but no linked effect supplies the trigger phase or critical amount; current CoA 490244 is a later active-summon revision, and reused 494051 is Purgatory Fire. See [the raw source/runtime audit](ROM_MAGE_FLAME_FOLLOWER_RUNTIME_AUDIT.md). Fire Ward (490248) follows the current CoA Mage page: it applies 11.5% less received damage across the six modeled magical schools to the caster and party within radius 100 (10 runtime units), leaving physical damage unchanged. The local RuneWaker component (500366) supplies +10 Fire resistance and a 600-second duration; CoA lists +230 at skill level 105 but gives no scaling curve, and the simulator has no skill-level state for Fire Ward, so +10 remains active rather than guessing intermediate values. Local cost/range/timing (120 MP, 150/15 runtime units, instant) are retained. The isolated catalog/aura test passed; two player/companion scope/radius runtime tests pass: player and generated-companion casts apply to self/nearby party members and exclude a distant member.
- **Druid:** Spirit of Life party HoT, Unity's guaranteed spell crit/healing and 15-second movement lock, Spirit Guidance's Nature Power gain, Savage Blessing's friendly target, Healing Arrows, source-backed Nature Power selection/spending for Fountain, Seeds, Wrath, Sandstorm, Earth Chain, Healing Wind, Poisonous Widow, Heart Piercing, and Cross of Thorns, plus Brilliance of Nature's 10-to-15 dynamic cap for the player and companion, have focused fixes. Weakening Seed and Withering Seed select exactly one local RuneWaker modifier branch per cast; each component maps to its own 20-second −2% target debuff. Caster-directed Nature Power drains are now distinct from hostile-target resource steals, preserving the source ordering for spends and refunds. Mage/Druid Green Guardian (494331) now follows the exact-pair current CoA active stack skill: player and companion actors gain one stack per full observed stationary second up to 20, for +1% movement speed per stack. Companion auto-use when its aura is absent is simulator policy. The old expiry HoTs are suppressed only for Mage-primary/Druid-secondary; the post-movement one-second gate is a timing approximation, and stack loss/MP refund remain unwired because CoA leaves the trigger and basis unspecified. See ROM_DRUID_MAGE_GREEN_GUARDIAN.md. An isolated CoA helper and 7 tests record Spirit Guidance 493536's no-player-target rule and reputation-based NPC conversion, plus Rebirth 493537's 30%, Advanced Rebirth 493559's 45% with Amulet of Light, and Supreme Rebirth 493560's 75% with Golden Amulet. These rules are not runtime-integrated: combat lacks NPC faction/reputation and player death-debt/item-consumption state. The CoA duration is listed only for one Spirit Guidance skill value, and basic Rebirth's optional amulet bonus is unquantified. Current CoA Druid/Rogue Necrotic Wound supersedes RuneWaker's old heal-reduction payload; see the source/rationale note. RuneWaker Druid proc gaps are now scoped: Revival Slash 499496's 25% hidden-child roll is source-resolved and runs once only when the original target survives the first group; the reduced hidden heal still lacks a complete native runtime formula; Quick Light Protection has no bound local hook and its ID is reused in current CoA; Boiling Rock has no linked proc payload; learned Inspiration Display child 499942 has an ordered 60%-gated effect and 30% fallback plus its timeout payload; this does not establish an automatic proc from public Inspiration or Spiritual Gush; local Avalanche remains open. Current CoA 494029 reworks the passive to apply Weakening Seed on CoA Rockslide 494063, distinct from RuneWaker Rockslide 493543; it publishes 18.8% generic defenses only at skill +105, with no lower-rank curve, defense school, or Nature's Power rider. Its first hit is delayed two seconds, while extra-hit timing is unspecified; Extended Recovery's six added seconds are implemented but its Nature's Power chance is open; Spring Flower's learned child 499935 has a bound Rand30 +1 Nature Power effect and a 1/3/5% max-HP expiry-heal chain; periodic healing remains blocked on native formula inputs. See [the source audit](ROM_DRUID_REMAINING_PROC_AUDIT.md). Current CoA Druid/Mage Inspiration (494322) now grants one deterministic stack per positive Nature's Power spend for the exact pair, capped at ten for ten seconds. Its modeled five-unit caster-centered radius and shared-stack refresh are explicit approximations; player/companion recipient and cast-haste integrations are tested. Fireball speed/resource riders remain unresolved per ROM_DRUID_MAGE_INSPIRATION.md. Current CoA reuses 494200 as Recovery Expert and changes Recover targeting/payload; its current Recover identity is 493528. Those later rules do not supply RuneWaker Extended Recovery's missing Nature's Power chance or event phase.
- **Warlock:** Aftermath remains covered for player and generated companions. Current CoA same-pair or explicit-rework behavior is now wired for Mind Transference 498642 (75 Rage → 6 Psi, 1-second cooldown); Divine Assistance 498668 (+16% magical damage and healing); Healing Fortune 498633 (landed Psychic Arrows grants +12% healing and +12% Wisdom for 20 seconds, and Warp Charge heals a friendly target); Psychic Rising Tide 498643 (Rising Tide becomes instant with a 5-second cooldown, grants 1 Psi, and a critical hit triggers Healing Fortune); Ring of Comfort 498641 (caster +1 Psi per accepted cast) and Mind Shield 498648 (caster +1 Psi on Urgent Heal; Defense Net duration reduction retained). Soul Enlightenment 498649 now uses the current CoA +5.7% damage dealt/+17.1% received healing aura for 30 seconds, 2 Psi, and a modeled 7.5-unit radius; player and companion casts are covered, while the Willpower Construct Caster restriction is tooltip-only because that state is not represented by cast validation. The local Mind Transference +40% physical-attack child rider is omitted because current CoA does not confirm it. Current CoA Rising Tide can route an ally-targeted cast to that ally's hostile target, but the simulator has no hostile-target selection state on party members, so only that redirect is unsupported and is called out in its tooltip. Psychic Warrior 499868 is the same Warlock/Warrior pair and ID as the local obsolete passive, now shown with the current name and tooltip. Its 187.5% area / 1,050% single-target main-hand DPS coefficients are recorded in an isolated helper; combat integration remains open: the isolated helper preserves both Physical and Dark tags, but CoA does not document hybrid defense order or added-hit cadence/roll inheritance; see the [source/runtime note](ROM_WARLOCK_WARRIOR_PSYCHIC_WARRIOR.md). The [12.1.4.1500 patch](https://chroniclesofarcadia.com/patch/12-1-4-1500) raised the area coefficient to 250%, and [12.1.5.1000](https://chroniclesofarcadia.com/patch/12-1-5-1000) reduced it to the current 187.5%. The additional attribute-gated main-hand damage for Slash and Consistent Heart Strike remains unmodeled because CoA gives no amount. Current CoA lists Enraged 499871 on the [Warlock/Warrior page](https://chroniclesofarcadia.com/en/wiki/skills/list/9-1) as Warrior General level 60: instant, 40-second cooldown, restoring 100 Rage, 35 Focus, and 1 Psi. It is a distinct learned row and reuses the generic capped resource effects for players and companions. RuneWaker Warrior General Enraged 490492 remains a separate same-name ability. Local 499869 is a level-70 Warlock/Warrior learned Mind Transference variant, not current-CoA Psychic Warrior or Enraged; no current-CoA mapping is established. Current CoA Warlock/Mage Soul Brand 498705 now handles any landed Fire damage (including periodic hits): it applies the capped, refreshing +2%-per-stack elemental damage-taken aura and restores 1 Psi to the triggering player or companion. Soul Brand Sting 498710 costs 2 Psi, gates on the tagged local Willpower Blade aura, adds 1× derived Intelligence to each Dark/Fire packet, and resets Flaming Heart Strike on cast. Warlock/Priest Spreading Pain 499856 consumes its +25% Magical Critical Bonus aura in the central player/companion spell-critical resolver, scaling the bonus portion of a 2.0 multiplier to 2.25; ordinary hits and crit chance do not change. See the feature notes for source conflicts and simulator mapping limits. The remaining CoA cost/range limits are Spreading Pain's 10% Mana cost (the RoM Warlock resource model has no Mana pool) and the unverified conversion of range 150 to local 22.5; Soul Brand Sting retains local range for the same reason. Current-CoA Warlock blockers remain Breathing Control 498634's Enraged chance/event phase/extra Focus; Deep Breathing Control 499870's 15% HP trigger/extra Focus; Mind Shield 498648's reset chance and Defense Net amount; Psychic Warrior 499868's hybrid mitigation, added-hit semantics, and unquantified attribute rider; and End of Thought's current-version contract. Local RuneWaker evidence is now distinct: learned Mind Shield guarantees the Ring reset after a landed Urgent Heal; local 499869 is level-70 Warlock/Warrior Mind Transference, not current-CoA Psychic Warrior or Enraged; and local End of Thought is Warlock/Rogue with a pre-hit threshold callback but no located timed-child consumer. Breathing passives still have no local trigger binding. These local contracts do not fill current-CoA gaps. Mind Transference 498642, Divine Assistance 498668, and current-CoA +1 Psi effects remain resolved; WoW Soul Leech (`talent-1678`) is separate. See the [local source follow-up](ROM_WARLOCK_SOURCE_FOLLOWUP_2026-10-02.md) and [current-CoA audit](ROM_WARLOCK_REMAINING_CONFLICTS_AUDIT.md).
- **Champion:** Fearless Blow's health/Rage gate, Rune Draw pull, Indomitable Spirit threshold, cooldown-reset scopes, rank-1 Forge trigger, Rune Pulse's 5 Rage on landed hit, Champion/Warrior Determination Rune's 30%-max-HP shield, and Rune Overload's local 15-Rage-per-second drain and zero-Rage termination have focused fixes. The Rune Overload child catalog entry now resolves hidden MagicCollect 498574 from component 621243 as a 0.6 physical-damage coefficient; catalog work also removed an unsupported 10-yard radius heuristic. Component 621241 links it as an on-time one-second tick, but runtime has no autonomous timer consumer for that link. The local description says the child hits nearby targets without a numeric radius or target cap, so scheduling and target scope remain unresolved rather than guessed. The current [CoA Champion/Rogue list](https://chroniclesofarcadia.com/en/wiki/skills/list/10-3) has a conflicting later ID mapping: CoA calls 498571 Rune Overload and 498572 Runecraft - Haste, while RuneWaker calls 498572 Rune Overload and 498571 Remodeled Body. CoA patch history confirms later revisions (Shield Form gate and Disassembly termination; Rage drain and damage changes), so the current CoA values were not imported into the RuneWaker model. Soul Forge Mystery activates its sourced +10% Shadow damage bonus for 10 seconds after a critical hit, while its five-minute physical-critical aura remains active. Way of Frenzy now grants +2% Stamina per landed Divine Vengeance hit, stacking to five for 60 seconds; its local tooltip and component supply the trigger, stack cap, modifier, and duration. Shield Form (498562) is source-learnable for Dwarf Champion at level 16 through flag 546211/quest progression, which the level-derived catalog does not model; its toggle/child runtime remains open. Rank-2 Forge and Chain Drive, Rune Pulse's one-second +20% outgoing-damage window, and Dark Energy Strike's 15% post-physical-result reset are source-backed and implemented. Rank-1 companion auto-attacks now emit owner/expiry-qualified events; a fully absorbed swing cannot proc, while a landed swing grants its own stack and +10 Rage before the ordinary +6. Focused Forge, Champion, and party-runtime tests passed 74 tests across three files. The next-Curse transform, complete Shield Form behavior, and Rune Overload target processing remain open. See [the source follow-up](ROM_CHAMPION_SOURCE_FOLLOWUP_2026-10-02.md) and [the source audit](ROM_CHAMPION_REMAINING_MECHANICS_AUDIT.md).
### Source-complete CoA mechanics with remaining runtime gaps
- **Warlock/Priest Spreading Pain (499856):** The current [CoA Warlock/Priest page](https://chroniclesofarcadia.com/en/wiki/skills/list/9-5) preserves the exact local skill name, ID, and pair and specifies the three linked debuffs, +18% Magical Attack Power, +25% Magical Critical Bonus, and Healing Fortune activation. Patch [10.6.1](https://chroniclesofarcadia.com/en/patch/10-6-1-1000) narrows that activation to Healing Fortune's healing-increase portion: +12% healing for 20 seconds, not its separate Wisdom or Warp Charge effects. The catalog/tooltip and player/generated-companion cast effects preserve the local linked children and apply the sourced +18% magical attack, +12% healing, and +25% Magical Critical Bonus. The central critical resolver consumes the tagged bonus aura only for magical spell crits: a 2.0 critical multiplier becomes 2.25 by increasing its bonus portion, with no change to crit chance or ordinary hits. The wiki also lists 10% MP plus 15 Focus and range 150, versus the local row's 15 Focus and range 22.5. RoM Warlock has no Mana pool and no general wiki-range conversion was verified, so those cost/range differences remain documented without an invented cost or range override.
- **Warlock/Rogue Shadow Slice (CoA rework of local Soul Raid 498678):** The official [CoA special-skills list](https://chroniclesofarcadia.com/en/wiki/basic-information/special-skills) confirms the skill is Warlock/Rogue level 30. Patch [10.4.0.4001](https://chroniclesofarcadia.com/patch/10-4-0-4000) explicitly maps Soul Raid to Shadow Slice and says it modifies Shadow Step (490344): a 1-second stun, 4,400 Dark hit, and +30% Dark damage/+10% movement speed for 30 seconds. Patch [10.4.1](https://chroniclesofarcadia.com/en/patch/10-4-1-1000) corrects its Psi recovery from 2 to 3. `romWarlockRogueShadowSlice.ts` encodes the source-gated hit, status, buffs, and resource rider; focused tests cover exact values and identity gating. The rework replaces Shadow Step's local teleport; the simulator can model the strike and effects but has no position state for the shadow-behind-target movement. CoA does not provide a lower-rank damage curve, so 4,400 is represented as the quoted flat amount with no invented level scaling. The generated catalog/tooltip and player/companion cast mechanics are integrated, replacing the local six-second +10% Dark/+10% movement rider when the passive is learned.
- **Warlock/Mage Soul Brand (498705):** Current CoA's same-name, same-ID, same-pair rework supersedes RuneWaker's three-skill trigger, 9% Dark/Flame-only debuff, and no-Psi payload. Player and generated-companion hooks now apply the current effect after positive landed Fire damage, including periodic events: +2% damage taken per stack for 20 seconds, up to four stacks, and +1 Psi to the source. The five available elemental-school mappings are Fire, Frost, Nature, Holy, and Shadow; Arcane and Physical are excluded. Focused helper/aura and runtime tests cover direct/periodic player and companion hits.
- **Warlock/Mage Soul Brand Sting (498710):** The current [CoA Warlock/Mage page](https://chroniclesofarcadia.com/wiki/skills/list/9-4) and patches [11.1.1.4000](https://chroniclesofarcadia.com/patch/11-1-1-4000) and [12.1.0.5000](https://chroniclesofarcadia.com/patch/12-1-0-5000) support the 2-Psi cost, 3737.5 + 1×Intelligence Dark and Fire packets, Willpower Blade requirement, and Flaming Heart Strike reset on cast. The exact-pair catalog/runtime now models those packets using each actor's derived Intelligence, gates use on an active locally tagged “Willpower Blade” aura, and resets on cast. This state-name gate does not equate local RuneWaker 497955 with CoA Willpower Sharpening 1494096. CoA range 150 remains unsupported because its unit conversion to the local 22.5 is unverified; the local range is preserved. Focused tests cover player and companion gates/amounts and the cooldown reset.
## Mechanics implemented in this follow-up
- **Rogue/Mage Chaos Dagger (491178):** The same-ID/name/pair [current CoA row](https://chroniclesofarcadia.com/en/wiki/skills/list/3-4) gives the landed normal-attack Fire packet as 169.4% of the attacking hand's weapon DPS; [patch 12.1.0.4000](https://chroniclesofarcadia.com/patch/12-1-0-4000) changes it to passive. Player and companion main/off-hand packets now go through the existing Fire resistance, aura, absorb, and death pipeline. This deliberately replaces RuneWaker's Enchanted Throw projectile/physical-child behavior for Rogue/Mage only. CoA's listed 25 MP has no published spend timing after the passive conversion; the simulator does not guess a per-auto debit. The separate temporary Physical Attack Power rider says only “slightly” and supplies no amount or duration, so it remains open. See [the source and rationale note](ROM_ROGUE_MAGE_CHAOS_DAGGER.md); 43 helper/player checks and one party integration case pass.
- **WoW Death Knight Merciless Combat (`talent-1993`):** Generated local rank rows supply the eligible abilities (Icy Touch, Howling Blast, Obliterate, Frost Strike), 6%/12% bonus, and strict target-health threshold below 35%, so no WotLKDB fallback was needed. Player and generated-companion direct-hit paths check each target's current health immediately before resolving damage and apply the rank bonus before mitigation. It does not modify Icy Touch's periodic Frost Fever tick; exact-threshold and unrelated-spell controls are covered. The parser cannot safely model this conditional as a global scalar, so the per-target hook is intentional. See [the source and integration note](WOW_DEATH_KNIGHT_MERCILESS_COMBAT.md); focused validation passed six tests.
- **WoW Mage Netherwind Presence (`talent-1846`):** Generated local ranks 44400/44402/44403 set 1/2/3% spell haste per stack, up to three stacks for 10 seconds. Because the generated 100%-chance Proc Trigger Spell rows lack proc-phase flags, the runtime awards one stack at accepted cast commitment; this is documented as an event-phase inference, and channels do not grant one stack per pulse. The generated tooltip's reachable Mage triggers are Arcane Missiles, Arcane Barrage, and Arcane Blast; Arcane Orb is missing from the catalog, while Moonfire/Starfire/Starsurge are non-Mage rows. At max rank, casting Slow with three stacks adds 30% movement speed for three seconds without consuming the haste stacks. The player movement controller and companion follow controller consume that aura; actual in-scene movement feel remains a manual playtest item. No WotLKDB fallback was used because stock 44400 is a different permanent +2% effect. Focused validation passed seven tests across two files; see [the feature note](WOW_MAGE_NETHERWIND_PRESENCE.md).
- **WoW Death Knight Spell Deflection (`talent-2018`):** Generated ranks supply the 15/30/45% School Absorb and school mask 126 (Holy, Fire, Nature, Frost, Shadow, Arcane); the tooltip supplies the dynamic proc chance equal to current Parry. The player and generated-companion incoming-hit paths apply one rank-scaled absorb on landed discrete enemy spell hits after existing aura/resistance reductions and before subsequent Ward/transfer/shield stages, and record it in absorbed combat damage. The current enemy model has no periodic incoming damage-tick event; future periodic spells must not use this direct-hit adapter. Integer flooring is labeled as a simulator choice, and an AzerothCore handler is used only as corroboration because it is a fork-specific reference. Focused validation passed seven tests across helper, player/companion integration, and Frost Warding regression files; see [the source/rationale note](WOW_DEATH_KNIGHT_SPELL_DEFLECTION.md).
- **RoM Mage/Druid Green Guardian (494331):** Current CoA behavior replaces the exact Mage-primary/Druid-secondary local passive: a zero-stack aura gains one stack per full observed stationary second, capped at 20, and each grants 1% movement speed. The full stationary second after a sampled position change is an explicit timing approximation; CoA says moving briefly pauses generation but gives no duration. The old Protection-expiry HoTs are suppressed only for this pair. Companion AI casts the skill through the normal ability path when learned and its aura is absent, a simulator policy. Stack loss and the 10% MP restore remain unwired because CoA does not define the loss event or percentage basis. Focused validation passed 29 tests and TypeScript emitted no diagnostics; see [the source/runtime note](ROM_DRUID_MAGE_GREEN_GUARDIAN.md).
- **Druid/Rogue Necrotic Wound and Sinister Request:** Current CoA behavior replaces conflicting RuneWaker payloads for this exact pair. Wound requires Corrosive Poison plus one Nature's Power, spends 4% Mana once at channel start, deals three 329.7% Dark hits over 1.5 seconds, spreads Corrosive Poison, and has no cooldown or old healing-reduction/root riders. Its three evenly spaced pulse timestamps are a documented approximation; CoA specifies hit count and duration, not timestamps. The channel completion check now tests only unspent costs, which fixes rejection after prepaid Nature's Power reaches zero. Sinister Request fills existing supported party resource pools to their caps in source radius 150, converted to 15 project units; patch 12.1.6.2004 supplies the current 15-second cooldown, and successful Wound/Poisonous Widow Embrace casts reduce it by one second. Player and companion paths respect the existing position/LOS selection and companion AI reacts to nearby depleted allies. CoA does not define the poison-spread duration-copy rule, so the simulator refreshes the full duration. The global 50% AoE multiplier is not represented. See [the source and implementation note](ROM_DRUID_ROGUE_NECROTIC_WOUND.md).
- **Rogue Poisonous Hands and Energized Hands:** The current [CoA Rogue page](https://chroniclesofarcadia.com/en/wiki/skills/list/3-1) and patches [12.1.0.4000](https://chroniclesofarcadia.com/patch/12-1-0-4000), [12.1.0.5000](https://chroniclesofarcadia.com/patch/12-1-0-5000), and [12.1.5.1000](https://chroniclesofarcadia.com/patch/12-1-5-1000) take precedence over conflicting RuneWaker rows for Rogue-primary IDs 490329 and 490347. Poisonous Hands builds up to ten target stacks while the target's damage-dealt reduction remains fixed at 8% total; each successful application also builds one 1% current-target attack-speed stack, and switching targets resets that self-ramp. Energized Hands supplies +100% Energy regeneration, +50% maximum Energy, +20% Energy costs, and −0.1 seconds to committed skill cooldowns. The local generated 50% proc chance is retained only as a fallback because CoA does not quantify “a chance.” The project has no Poison Bottle inventory; CoA gives no faster-main-hand cast-time formula, so the 1-second tooltip cast is the current fallback; and the cooldown subtraction timing is an implementation choice documented in [the feature note](ROM_ROGUE_POISONOUS_HANDS.md). Player/companion focused validation passed 49 tests.
- **Priest-primary Holy Candle (490304):** Current CoA values and patch 12.1.6.2000 set +27% healing, 5% Mana activation cost, range 1, a 30-second cooldown, and 12% self-damage; the CoA developer reply sets its per-owner limit to once per second. The local 60-second duration is retained because CoA omits duration; the old +5% modifier and free-running HP drain are replaced. Accepted healing casts charge once before target fan-out, with per-owner throttling across spells; full-health targets count, invalid or interrupted casts do not, HoTs charge at application rather than each tick, and channels use a persistent per-cast guard. The max-health basis is an explicit interpretation because CoA does not specify current versus maximum HP. Tests cover player/companion, AoE fan-out, overheal, failure/interruption, HoT ticks, and a channel scheduler boundary; the Divine Hymn channel is a test fixture only. See [the rationale](ROM_PRIEST_HOLY_CANDLE.md); focused validation passed 16 tests across three files.
## Visual review and evidence limits
- Spell effect manifest counts above identify mapped source assets and browser-renderable graphs. They do not certify perceived brightness, screen coverage, or combat readability. WoW phase graph coverage is strong for mapped ranks; Shaman has the largest graph gap (149/251 mapped rank rows), followed by Hunter (125/157).
- The original WoW Flash Heal impact and Arcane Explosion cast-start sphere, plus RoM Plasma Arrow and Electric Bolt impact models, were inspected in the development preview. Their selected phases are tuned; other WoW spell visuals still need a per-spell rendered review.
- Hunter graph metadata shows Arcane Shot/Aimed Shot using a five-emitter/two-ribbon ArcaneShot_Missile release (particle max scale about 0.26) and the shared Magic_Impact_Chest impact (max scale about 1.76, peak alpha 1); Volley uses a 16-emitter/four-ribbon release (max scale about 0.26) and Magic_Impact_Chest/ArcaneShot_Area impacts (ArcaneShot_Area max scale about 0.83). The Beast Within cast graphs report Magic_Cast_Hand max scale about 0.45 and BeastRageCaster about 0.96. These are extracted graph values only: the Hunter review's CUA browser inventory exposed no browser, so no rendered size/brightness verdict was recorded.
- Warrior evidence gap: Bloodthirst and Sweeping Strikes have focused catalog/runtime regression coverage, but the remaining Warrior abilities/talents have not received a complete runtime pass, and Warrior spell size/brightness has not received per-spell rendered review.
- RoM visual review remains limited: only a subset of active source effects have browser-renderable graphs. A class-by-class size/brightness verdict cannot be derived from source file names or default `1x` tuning. Most RoM spells still need per-spell visual review.
- Verification is against the local simulator/runtime and extracted catalogs, not an official WoW or RoM server. The focused tests validate selected fixes; they do not prove every class ability or talent works.
## Focused validation (2026-10-02 reconciliation)
Current aggregate verification passed 382 focused tests across 35 files with four existing IndexedDB skips; Ready-five passed 7 Vitest and 20 Python tests. The 8 GB TypeScript check, prebuild asset audits, and full production build passed after the narrow Hunter summon-card CSS correction. All four earlier baseline assertions and current catalog/count assertions now pass. The previous 202/20 test run and 63-path release check are historical, not the latest aggregate. The rank-1 Forge companion event-gate correction is implemented; its focused Forge, Champion, and party-runtime tests passed 74 tests across three files, and Ready-five passed again after the fix. These are overlapping selections and are not summed. The final post-fix 8 GB TypeScript/Vite build passed with prebuild asset audits and bundle verification. Exact-final-dist Cat QA replay also passed. `npm run release:check` passed for 94 changed paths, including untracked files. See [the current follow-up report](MECHANICS_BACKLOG_FOLLOWUP_2026-10-02.md).
The earlier fresh-dist Turtle UI checkpoint passed in a loaded scene at 390×844: its selector card spanned y=306–420, clearing the party row ending at y=269 by 37px without overlapping the top-right HUD. The selector stayed disabled during real Wailing Caverns combat; afterward it selected Turtle, showed Shell Shield 26064 and no Furious Howl, and persisted through reload while a second character remained Wolf. There were no page or network errors apart from a favicon 404 and no horizontal overflow. The UI-created Marksmanship characters were raised to level 10 for this mechanics diagnostic; this was not Ready-party or balance certification. At that checkpoint, Escape/Spellbook Call/Revive had not yet been verified.
Final Cat UI QA on the exact final production build passed for native family/reaction selectors, mouse Stay/Follow, Growl, encounter lock, and Cat persistence after reload while a second character remained Wolf. In the final narrow view, the party row ended at y=269 and the selector card spanned y=306–420 (37px clearance); there was no top-right overlap or horizontal overflow, and the canvas was loaded. Escape opened pause, Spellbook opened, the actual Call Pet entry was clicked, and the overlay closed with Cat still present. This verifies that activation route, not summoning after the pet is absent. Revive was untested because the pet did not die. No live Rake/Prowl cast or Cat model appearance was verified; the only console error was favicon 404, with no page or HTTP errors.
The initial clean-baseline check reproduced four assertions: Divine Punishment produced an extra catalog entry, God's Vengeance lacked its expected proc, the Mage/Druid elite milestone repeated 25 instead of advancing to 30, and Speed Catalysis restored no Energy. All four assertions now pass in the current aggregate, as do the catalog/count assertions. The initial outcomes remain historical; the current status is in [the follow-up report](MECHANICS_BACKLOG_FOLLOWUP_2026-10-02.md). The full `npm test` suite and all-class balance sweeps were not run. Focused tests validate only their named paths and do not certify every ability or talent.
## 2026-10-03 — Native RoM combat follow-up
The requested five identities now share native source amount dispatch and exact-pair rotation policies across the active player and party NPCs. Ordinary RoM NPC pools contain only those five classes; explicit configured factories retain the broader catalog for targeted work. Native-mode health budgets are independent of the preserved WoW-stat RoM curve. The fixed full-player diagnostic completed 80 pulls with no deaths or invalid casts; this does not certify scene encounters or promote readiness.
Focused native integration, stat-mode compatibility, party, source catalog, Ready-five, and avatar checks passed. The separate `combatRotation.test.ts` still has one existing unsupported-only Rogue Killing Spree signature assertion failure (30/31 pass); this RoM pass does not implement Combat Rogue. The full suite/all-class balance sweeps were not run. Source boundaries and final build/browser evidence are recorded in [the combat report](ROM_NATIVE_COMBAT_PASS_2026-10-03.md) and `PLAYTEST_NOTES.md`.
+276
View File
@@ -0,0 +1,276 @@
# Active Class Mechanics Backlog
Updated 2026-10-07. This document lists unresolved ability and talent mechanics for all ten WoW 3.3.5a classes and all ten RuneWaker primary classes. It excludes completed fixes and all visual or sound review. Some items need source confirmation or simulator support before they can be implemented; do not guess missing values. For RoM conflicts, prefer clearly matching current Chronicles of Arcadia behavior over the RuneWaker snapshot; verify skill identity and class pairing, and document the source and any simulator approximation. See [the full audit](ACTIVE_CLASS_AUDIT.md) for the supporting findings and source conflicts.
New routine mechanic/browser diagnostics use **Stormwind Stockade: Cellblock Rush** (`bite-sized-stormwind-stockade`). Each run selects one of the five Stockade bosses from its shared run ID, so record the boss actually observed. Import `scripts/playtest-defaults.cjs` and follow [the test policy](TEST_DUNGEON_POLICY.md); full Stockade campaigns require explicit selection. Isolated Boss Testing remains a separate mode that defaults to Hamhock. Historical Wailing findings below do not select future tests.
## Targeted follow-up (2026-10-04)
- [x] Correct pinned AzerothCore creature-immunity foreign-key decoding. Lady Anacondra is Fear/Horror immune, not Silence/Interrupt immune; the source-registered Lightning Bolt regression now cancels under Vow of Silence. Actual Silence/Interrupt-immune creatures retain protection. See [the audit](VOW_OF_SILENCE_AUDIT_2026-10-04.md).
- [x] Verify Vow against Lady's actual scheduled Lightning Bolt and the full 8.4-second silence window. The live check exposed Nature Thorns bypassing spell-kind-only selection because its source delivery is melee; the corrected school/kind gate suppresses new magic casts while preserving physical attacks. Final-build replay confirms cancellation, no nonphysical cast during the status and natural Nature cast resumption after expiry. See [the live report](ROM_VOW_LIVE_FINAL_2026-10-04.md) and [cast-gate source note](ENEMY_SILENCE_CAST_GATE_2026-10-04.md). Boss Testing proof is separate from normal campaign/full-clear coverage.
- [x] Diagnose owned native Priest sustain at levels 60/80 across six consecutive-pull/rest scenarios. All clear without deaths or empty healer Mana; effective healing, overheal and actor attribution are recorded separately. No recovery or healing-AI tuning was justified. See [the audit](ROM_NATIVE_SUSTAIN_AUDIT_2026-10-04.md).
- [x] Audit the Killing Spree representative-signature failure. Spell 51690 is a source periodic-dummy selector with a dedicated player `class-script` handler; the test now checks that exact mechanism while preserving the ten-strike runtime regression. Correct the player damage aura from 1% to the linked DBC child 61851's 20% for two seconds. See [the audit](WOW_KILLING_SPREE_AUDIT_2026-10-04.md).
- [x] Implement shared timed player/companion Killing Spree: five assaults at application and 500-ms intervals through two seconds, retained cast-time target pools, owner-local cleanup, linked +20% final-pulse ordering, actual player/NPC relocation, and learned companion AI selection. Seeded target selection, estimated weapon-child damage/teleport coordinates and unverified active-control semantics remain simulator limits. See [the parity report](WOW_KILLING_SPREE_PARITY_2026-10-04.md). This Combat Rogue diagnostic does not expand Ready-five.
- [x] Audit the five active native RoM identities and correct Knight/Scout Blood Punishment to current CoA's +15% healing received and +5% Holy damage on the actual Blood Arrow aura. Correct companion RoM direct-hit school selection and no-roll outgoing damage-aura consumption; native and compatibility NPC casts are covered separately. See [the five-class report](ROM_FIVE_MECHANIC_GAPS_2026-10-04.md).
- [x] Reconcile Blood Arrow for the verified Scout/Rogue and Knight/Scout owners: indefinite owner-local toggle, recast/right-click cancellation, 10-second cooldown after deactivation, and no legacy idle drain. Knight/Scout offensive ranged-weapon skills charge 2% max HP plus 1% max MP; Scout/Rogue damaging ranged skills and owned NPC ranged auto swings charge 2% max HP without the MP surcharge. Base definitions and resolved ranks are scoped to those pairs; unverified owners retain the RuneWaker behavior. See [the implementation report](ROM_BLOOD_ARROW_TOGGLE_2026-10-04.md).
- [x] Implement recurring Scout/Rogue player Auto Shot through the learned primary skill: ranged Physical events, supported native weapon DPS/cadence, automatic Training Gear and compatible custom-item fallback, native/compatibility haste, owner-local Blood Arrow HP cost, stop/retarget/reset/death cleanup and no simultaneous melee swings. Thirteen focused checks pass; see [the implementation report](ROM_PLAYER_RANGED_AUTOSHOT_2026-10-04.md) and [the coordinated follow-up](ROM_HEALING_PARTY_RANGED_FOLLOWUP_2026-10-04.md).
- [ ] Source Auto Shot's contribution from the last offensive skill before implementing it. Current CoA specifies only an unspecified portion, without a coefficient. The implemented player mode uses the sourced 80% ranged weapon DPS term; local range and runtime constraints are documented in [the implementation report](ROM_PLAYER_RANGED_AUTOSHOT_2026-10-04.md).
- [ ] Establish Blood Arrow's current damage formula through rank 80 before replacing the local 10% aura. Current exact Scout/Rogue and Knight/Scout pages publish only +104.5% at maximum skill rank 105; the historical local component supplies one +10% value. Neither establishes a cap-80 curve. See [the source audit](ROM_BLOOD_ARROW_SCALING_2026-10-04.md).
- [x] Correct native-five companion selection to exclude the player's active pairing when the remaining identities can fill all requested role seats. Entry and avatar preloading now pass the exact pair; all five supported player complements and fallbacks pass focused coverage. See [the selection report](ROM_NATIVE_PARTY_SELECTION_2026-10-04.md). The prior Scout/Rogue duplicate is historical evidence; readiness and the native pool remain unchanged.
- [x] Propagate Group Heal's sourced 12 m radius to its party-heal effect for player and NPC execution. Focused tests cover the inclusive 12 m boundary, exclusion at 12.01 m, living/LOS rules and both actual cast paths while preserving Soul Source's fallback. See [the radius report](ROM_GROUP_HEAL_RADIUS_2026-10-04.md). The earlier Stockade tank death remains a separate timing inference, not a proven range/LOS rejection.
- [x] Prevent the thirteen audited utility/extra-attack NPC spells from falling back to direct hits. Exact Ascension/Epoch signatures preserve each source profile; the second pass removes another 51 false attack rows and corrects 30 real attack/control rows, including hostile melee range, pure Kick interruption, caster-centered fear/stun and Chain Lightning range. Real damage and mixed-damage Shield Slam remain. Catalog regeneration also refreshes the existing damage-school/kind metadata. See [the source audit](STOCKADE_UTILITY_ATTACK_AUDIT_2026-10-04.md).
- [x] Implement enemy Chain Lightning 421's three total targets, nearest visible living jumps within 10 m, no repeated recipient, captured cast victim and profile-specific 0.6/0.7 decay. Preserve the first hit's existing amount policy. See [the Chain Lightning audit](STOCKADE_CHAIN_LIGHTNING_2026-10-05.md).
- [x] Implement sourced Rend 6547/16509: five physical bleed ticks at three-second intervals, no initial damage, ordinary refresh restarting the timer, independent casters, armor bypass and no magic dispel. Spell 16509 uses the strict source creature BaseDamage ratio through level 80. See [the Rend audit](STOCKADE_REND_2026-10-05.md).
- [x] Implement verified Enrage and Demoralizing/Battle Shout source modifiers and geometry. Enrage uses 120 seconds and physical damage plus melee-auto haste; source percentages multiply and repeated nonperiodic copies do not stack. Keep each Ascension/Epoch contract distinct. See [the enemy buff audit](STOCKADE_ENEMY_BUFFS_2026-10-05.md).
- [x] Resolve Chronomancer's pre-existing maximum-mana mismatch by consuming its structured permanent passive resource modifier. Aura 132 preserves its named resource, so Sun Cleric Rage and Necromancer Runic Power do not expand Mana. See [the resource report](CHRONOMANCER_RESOURCE_BASELINE_2026-10-05.md).
- [x] Implement sourced exclusive NPC Defensive/Battle Stance and ordinary WoW creature auto-attack blocking, including Improved Blocking's +75 percentage points for six seconds, actual facing/control/cast/NO_BLOCK gates and one level skill adjustment. Stockade Battle applies before combat; Kam's Defensive is one-shot. Native RoM attackers share the ordinary WoW target path. See [the implementation and limits](ENEMY_STANCES_BLOCKING_2026-10-05.md).
- [x] Implement source-bound direct physical NPC spell blocking for actual player and party casts, with per-rank WoW/Ascension metadata and an independent post-hit roll that preserves crit-plus-block. See [the source and runtime contract](NPC_SPELL_BLOCKING_2026-10-05.md).
- [x] Implement sourced enemy Bloodlust 6742: one engaged friendly creature, thirty-second Magic aura, independent +30% melee haste factor, retained self and missing-buff SmartAI rows, and actual Priest dispel. See [the utility continuation](ENEMY_WEAPON_UTILITIES_2026-10-05.md).
- [x] Implement enemy Disarm 6713's profile-specific weapon channels and cast requirements, WoW-ruleset unarmed main-hand autos, and Infected Wound 17230's Disease aura with +6 physical damage before armor/block/absorbs. Equipped items and nonweapon stats remain intact. Source and native amount limits are recorded in [the debuff audit](ENEMY_WEAPON_DEBUFFS_2026-10-05.md).
- [x] Implement explicit enemy Dual Wield 674/29651 with a separate half-damage offhand timer, and Thrash 3391's two independent queued main-hand swings. The source set does not establish Targorr's Thrash cadence; the existing template schedule remains simulator policy. See [the extra-attack audit](ENEMY_EXTRA_ATTACKS_2026-10-05.md).
- [x] Connect source-bound Disarm weapon aura and permitted selected-hand formula views for players and generated party members. Add verified native active-five main-hand unarmed inputs, hand-specific enemy results and committed combat-time evidence, and pinned flag-driven offhand capability. Keep nonweapon stats and usable hands intact. See [the weapon parity follow-up](WEAPON_PARITY_FOLLOWUP_2026-10-05.md) for source, gear, recorder and native rate boundaries.
- [x] Consume source-bound ordinary NPC ignore-hit-direction and critical-block inputs, roll critical block independently after a successful ordinary/direct-spell block, and preserve separate explicit-victim/area recipients for triggered shouts 5246 and 19134. Player/party auto results now include actual hand metadata; QA matches results to committed Disarm windows. Whole Critical Block/Deterrence imports remain gated by unsupported siblings. See [the continuation](ENEMY_SOURCE_PARITY_CONTINUATION_2026-10-06.md).
- [x] Audit hostile-NPC outgoing threat against the current target path. The source scales a recipient's threat list; current enemy recipients are playable player/party actors or owned summons. NPC-vs-NPC requires a separate future consumer. See [the source boundary](HOSTILE_NPC_THREAT_BOUNDARY_2026-10-06.md).
- [x] Recover the matching pinned enemy equipment table, validate virtual slots against Item.dbc, retain explicit source spawn GUIDs, and enable AUTO offhand attacks for proven ordinary NPC offhand weapons. Selectors and alternate entries fail closed; runtime tests cover independent timing and reset persistence. See [the equipment source mapping](ENEMY_EQUIPMENT_MAPPING_2026-10-06.md).
- [x] Add guarded ordinary-Creature self-cast Critical Block 47294–47296 imports, exact WoW335 Shield Bash 72 full utility blocking for player/party writers, and source shout aura 31 +25% speed with whole-spell fear immunity and separate stun-effect immunity. No source NPC Critical Block assignment was found, so no creature cast is invented. The stance/Thrash audit confirms no source meaning for Ascension DUMMY +42 or exact Targorr Thrash cadence; keep both gated. See [the utility/control completion](ENEMY_UTILITY_CONTROL_COMPLETION_2026-10-06.md).
- [x] Import exact WoW335 Shield Bash 72's child 29703 as a six-second 50% SNARE, integrate safe source-informed fear routes for local player/party/mobile summons, and bind named-shout immunity purge/escape to exact Berserker Rage 18499 and Bladestorm 46924 source grants. Whole child/rider removal, overlapping generic controls, blocked paths, expiry and accepted grant/cast consumers are covered. Icebound Fortitude has no sourced purge flag; Bladestorm has no controlled-casting bypass. See [the control-runtime follow-up](ENEMY_CONTROL_RUNTIME_FOLLOWUP_2026-10-06.md).
- [x] Add exact Lichborne player/party cast bypass and named-shout purge, source-bound Kick 1766/Pummel 6552 blocking, removal of Kick's prototype damage/duplicate interrupt, and actor-local pacify gates for weapon autos. The public `rogue-kick` ID persists. Audit Deterrence 19263's linked 67801 package while keeping its playable deflect import gated. See [the control/utility continuation](CONTROL_UTILITY_CONTINUATION_2026-10-06.md).
- [x] Import selected Hunter Deterrence 19263 with linked 67801 for actual player/companion casts, five-second owner-local lifecycle, parry/ranged-hit inputs and exact-source direct spell deflection. Preserve sourced pacify distinctions, off-GCD/cooldown/equipment rules, defensive NPC selection and hostile-rider suppression. Raw hit flags now reach normalized WoW attacks. See [the integration](DETERRENCE_INTEGRATION_2026-10-07.md).
- [ ] Extend utility full hit tables/ranks/profiles only with exact source proof. General shout Magic hit/resist/deflect, ordinary miss/resist control-rider fidelity, exact server flee paths/RNG, Charm/general immunity-grant purge rules, private Ascension stance DUMMY consumer, exact source Targorr Thrash timing, native custom equipment/rate and cast prerequisites, and broader weapon/proc formulas remain open. False direct hits stay omitted for unsupported effects. See [the current boundaries](DETERRENCE_INTEGRATION_2026-10-07.md).
## Native stat input update (2026-10-03)
RoM characters now retain an independent stat ruleset: existing saved characters stay on WoW compatibility, newly created RoM characters use native RoM, and the main-menu selector can change the choice safely. Native source stat channels and selected source gear inputs are available without treating native combat points as WoW ratings. The shared dungeon combat adapter and remaining native healing/combat boundaries are documented in [the ruleset implementation](CHARACTER_STAT_RULESETS_2026-10-03.md) and [the source contract](ROM_NATIVE_STATS_SOURCE_2026-10-03.md). This does not complete the Druid/Warden HolyHeal mechanics below, implement matchmaking, or promote RoM readiness. The dated October 2 source reports remain historical evidence.
## WoW 3.3.5a
### Hunter
- [ ] Complete the remaining WoW 3.3.5a Hunter pet mechanics for player Hunters and generated Hunter companions. The current player selector supports persisted Wolf, Turtle, and Cat profiles, including Turtle's source-backed Shell Shield; generated companions remain Wolf. Still needed: full family-ability coverage beyond the partial Wolf/Turtle/Cat profiles, stable, feed/happiness persistence, training mechanics, and pet critical-stat inheritance. The source extract contains 40 family rows, 32 of which the local core classifies as Hunter pets; this does not make all rows playable. No stock owner-crit inheritance rule was established.
- [x] Audit pet critical inheritance sources: local 19591 “Tamed Pet Passive 06” has zero-valued melee/spell crit aura amounts, and stock 3.3.5 core uses pet base crit plus the pet's own auras without an owner-crit formula. The proposed owner-melee-crit formula is only from an unmerged server issue; do not import it as stock behavior. Pet critical-stat inheritance itself remains unresolved.
- [x] Hunter pets dynamically inherit 45% of owner stamina (+10 pet health per inherited point) and 22% of owner ranged AP as pet AP for player and companion summons. The pet profile recalculates when owner stats or auras change.
- [x] Wolf Bite adds 7% of effective pet AP to the local rank's base damage. Local AzerothCore `spell_bonus_data.sql` rows 17253–17261, 27050, 52473, and 52474 supply that coefficient; temporary pet AP effects such as Furious Howl are included.
- [x] Kill Command uses local 3.3.5a Spell.dbc rows 34026/34027 and triggered child 58914: +60% pet special-attack damage for 30 seconds, reduced by 20 percentage points when a pet special is executed, with a 60-second cooldown. Three Bite executions therefore use +60%, +40%, then +20%; ordinary melee swings do not consume the rider.
- [x] The shared Wolf/Turtle baseline selects the highest local Bite rank available at the pet's level (1–80), charges the DBC-listed 25 Focus, and keeps its 1.5-second pet global cooldown independent of ordinary swings. Mend Pet's periodic heal is routed to the living active pet for player and generated companion Hunters; Revive Pet restores a dead pet at the modeled 15% health.
- [x] Wolf Furious Howl selects the local level-appropriate rank, costs 20 Focus, buffs the Wolf and master with the DBC-listed AP for 20 seconds, and recovers in 40 seconds without starting the pet GCD. The pet-side AP adds `rank AP × 2 / 14` damage to each 2-second auto swing using stock [TrinityCore `Pet.cpp`](https://github.com/TrinityCore/TrinityCore/blob/3.3.5/src/server/game/Entities/Pet/Pet.cpp) and [`StatSystem.cpp`](https://github.com/TrinityCore/TrinityCore/blob/3.3.5/src/server/game/Entities/Unit/StatSystem.cpp); Bite separately receives its 7% pet-AP coefficient.
- [x] Extract the local 3.3.5a Hunter-pet family and skill rows: 40 named families, of which the pinned core's `petTalentType` test identifies 32 as Hunter families. Wolf, Turtle, and Cat are selectable player profiles. The player choice is stored in the character profile, legacy/unsupported values default to Wolf, and changing families is locked during an encounter. Player Call/Revive preserves the choice; generated Hunter companions remain Wolf. See [the source/runtime note](WOW_HUNTER_PET_FAMILIES.md).
- [x] Add the selectable Turtle profile: it shares Wolf's local Bite ranks and has Shell Shield 26064 (0 Focus, 12-second duration, 60-second cooldown, 50% less damage taken). Shell Shield autocast while engaged is a pet-AI policy. Wolf alone has Furious Howl. Cat's Claw, Rake, and Prowl are modeled; other extracted families remain unselectable until their distinct abilities and runtime requirements are modeled.
- [x] Hunter pets inherit spell damage at 12.87% of owner ranged AP. Bite applies local AzerothCore coefficients of 0.119658 spell damage and 0.07 pet AP for player and generated companion Hunters.
- [x] Player Hunter pets expose Attack/Follow/Stay, Defensive/Aggressive/Passive, and Growl autocast controls (Growl starts off). Target decisions consume the owner's executed hostile-action event, retain a living victim until it becomes invalid, and use the local rank-specific Growl Focus/cooldown/flat-threat rows without a hard taunt; generated companion Wolves start Follow/Defensive and receive only their own owner's action events.
- [x] Player and generated-companion Hunter pets apply stock-compatible inherited defenses on incoming hits: the pinned TrinityCore 3.3.5/TDB profile supplies pet level-based armor/Agility, 35% of the owner's effective armor, and 40% of the owner's five modeled magical resistances. Holy remains zero because character stats have no Holy-resistance field. Other summons keep their prior mitigation path. This uses a pinned TrinityCore implementation baseline, not direct Blizzard-server evidence; see [the source/runtime note](WOW_HUNTER_PET_DEFENSE_INHERITANCE.md).
- [x] Go for the Throat (`talent-1818`) grants the generated 15/30 Focus after a qualifying Hunter melee/ranged critical strike, with a two-second Hunter-owner cooldown and the active living pet's Focus cap. Player and generated companion paths are wired. Companion roll setup covers the baseline ranged swing and the exact generated direct attack map (Aimed Shot, Arcane Shot, Auto Shot, Chimera Shot, Counterattack, Kill Shot, Mongoose Bite, Multi-Shot, Raptor Strike, Scatter Shot, Silencing Shot, Steady Shot), requiring its mapped attack kind. Party integration covers the baseline ranged swing and Arcane Shot; the current Marksmanship AI does not select Raptor Strike. Traps, Stings, Volley, and unclassified spells remain excluded, even if a generic event labels them ranged; a ranged-labeled Explosive Trap regression verifies this gate. The owner-scoped cooldown surviving pet swaps is an architecture inference.
- [x] Bestial Discipline (`talent-1390`) increases the active tamed Hunter pet's Focus regeneration by the generated 50%/100% ranks (5 baseline → 7.5/10 Focus per second) for player and generated-companion Hunters. Focus accrues continuously through the existing elapsed-time pet pool; the source gives no discrete tick cadence, so this is a runtime integration inference. The separate Intimidation Mana-cost rider remains scoped to Intimidation by the existing talent modifier parser.
### Priest
- [x] Lightwell rank-6 Renew child (48085) uses 0.626 spell power per tick. Local Spell.dbc supplies the 1,540 base heal and two-second cadence but has zero coefficient fields. The exact [WotLKDB 3.3.5a entry](https://wotlkdb.com/index.php?spell=48085) identifies child 48085 as Rank 6 and lists 62.60% spell power per tick; this is direct evidence for rank 6, not an inference from sibling 48084 or 28276. The runtime and focused profile test now use 0.626.
- [x] Current CoA Priest-primary Holy Candle (490304) uses +27% healing, a 5% Mana activation cost, range 1, 30-second cooldown, and the local 60-second aura duration because CoA publishes no duration. Patch 12.1.6.2000 supplies the current 12% self-damage; a developer reply confirms a one-second owner throttle. Player and generated-companion casts pay once per accepted healing cast, regardless of target fan-out; HoTs charge on application rather than ticks, and channels keep a per-cast guard. The maximum-health basis is an explicit local interpretation because CoA does not say current versus maximum HP. The old +5% aura and free-running -6% HP dot are replaced. The focused CoA Priest suite passed 16 tests across three files; see [the source and runtime note](ROM_PRIEST_HOLY_CANDLE.md).
### Death Knight
- [ ] Continue the remaining conditional, pet, and disease talent pass. Blood-Caked Blade is wired for player and companion autoattacks, and Epidemic extends both Death Knight diseases for player and companion casts.
- [x] Reaping (`talent-2001`) uses generated rank chances 33/66/100%, trigger spells Blood Strike (45902) and Pestilence (50842), and the local aura type 226 30-second period. WotLKDB 56835 confirms a 30-second Periodic Dummy with duration `n/a`; the timer is a refreshable removal tick, not a rune duration. The pinned [AzerothCore-derived handler](https://github.com/mod-playerbots/azerothcore-wotlk/blob/e822d718322289dd036fb2daf8867ba41283bf9a/src/server/scripts/Spells/spell_dk.cpp#L2640-L2705) converts one base Blood rune just spent, restores a Reaping-owned rune immediately on a successful landed spend, and retains it after a miss until expiry. Player and companion paths use independent conversion owners so Reaping expiry does not erase Blood Tap; Blood Strike's second damage packet cannot re-restore the rune. Companion Blood adds Blood Strike as a final trigger fallback only with a learned rank and ready base Blood rune; Pestilence is available only when it can spread that companion's active disease to another engaged target within the local 10-yard circle. Pestilence utility casts treat an actual disease transfer as the landed event because they have no damage packet. Focused tests cover helper ownership/expiry, player and companion Blood Strike, companion selection, and player/companion Pestilence spread. The core link is an AzerothCore-derived fork reference, not pristine TrinityCore behavior.
- [x] Bloody Vengeance (`talent-1944`) uses generated ranks for +1/2/3% physical damage per stack, a three-stack cap, and rank-specific 15/30/30-second duration. Any positive landed critical damage from a generated Death Knight player or companion event adds one source-owned stack after the hit; companion autos and direct damaging abilities receive combat-result rolls while talented. No WotLKDB fallback was needed. Party channel pulses only proc when their combat path produces a critical result; deterministic periodic damage without a crit result cannot trigger it.
- [x] Desolation (`talent-2285`) reads each rank's generated +1/2/3/4/5% all-attack damage bonus and 20-second duration, then applies the linked 100%-chance child aura after a landed Blood Strike for players and generated companions. The landed/main-hand gate is corroborated by the WotLK simulator's [`blood_strike.go`](https://github.com/wowsims/wotlk/blob/master/sim/deathknight/blood_strike.go); local generated talent rows do not specify the proc phase. This simulator has one primary Blood Strike action and no separate off-hand strike event. No WotLKDB fallback was needed because the local generated payload contains rank amounts, duration, and child IDs.
- [x] Blade Barrier (`talent-2017`) uses the generated 1/2/3/4/5% all-damage reduction for 10 seconds and the rank child links 51789/64855/64856/64858/64859. The aura triggers only on a real base-Blood-rune transition: a base Blood rune that was ready enters cooldown, and both base Blood runes are cooling after the committed action. This tracks original Blood runes, not Blood-cost runes: a Death Rune paying Blood cost while both base Blood runes were already cooling cannot refresh the aura. Player and generated-companion casts use the same transition gate and their own ranks. No WotLKDB fallback was needed. Four helper tests and two integration tests cover ranks, duration, reduction, player activation, companion activation, and Death Rune exclusion.
- [x] Merciless Combat (`talent-1993`) applies the generated 6%/12% bonus to Icy Touch, Howling Blast, Obliterate, or Frost Strike only while the current target is below 35% health. The generated rank rows supply the exact named spells, strict threshold, rank values, and child spell IDs, so no WotLKDB fallback was needed. Player and generated-companion direct damage paths apply the bonus before target mitigation; helper and integration coverage verify rank behavior and the exact 35% boundary. See [the source/rationale note](WOW_DEATH_KNIGHT_MERCILESS_COMBAT.md).
- [x] Spell Deflection (`talent-2018`) reads generated 15/30/45% school-absorb ranks and the 126 nonphysical school mask, then rolls once per landed direct incoming spell hit against the defender's live Parry chance. Player and generated-companion paths apply it after existing resistance/aura reductions and before later Ward, transfer, shield, and health-loss stages; absorbed damage is recorded. The discrete enemy attack model has no periodic incoming spell-tick event, so its current spell-hit event is the direct-hit boundary. Whole-damage floor rounding is a simulator choice; AzerothCore is corroboration, not stock-source authority. Focused validation passed 7 tests across three files; see [the source/implementation note](WOW_DEATH_KNIGHT_SPELL_DEFLECTION.md).
- [x] Epidemic applies its local generated 3/6-second duration increase as one/two extra three-second ticks to Blood Plague and Frost Fever.
- [x] Wandering Plague (`talent-2003`) now runs for player and generated-companion Death Knights on positive Blood Plague/Frost Fever ticks. Generated ranks deal 33/66/100% of the tick as Shadow area damage within 8 yards; proc chance equals the owner's current melee critical chance, with the corroborated one-second owner cooldown. The splash cannot recursively proc, and damage-breaking statuses exclude targets. See [the source/runtime note](WOW_DEATH_KNIGHT_WANDERING_PLAGUE.md).
- [x] Hysteria (49016) follows current Area-52 talent node 1954: +15% physical damage with 1% max-health loss per second for 30 seconds; the conflicting stock class row's +20% is not used.
- [x] Resolve Dancing Rune Weapon (49028)'s local payload: generated Spell.dbc gives 60 Runic Power, instant cast, 30-yard range, a 12-second summon, and a 90-second cooldown; its tooltip references child 51906, whose third effect reduces the Rune Weapon's damage by 50%. The parent's 10-point effect is Dummy, not mitigation. [WotLKDB 3.3.5a](https://wotlkdb.com/index.php?spell=49028) confirms the cost, duration, range, cooldown, and parent effect structure. A half-damage helper and source-gated mirror-event predicate are implemented and tested.
- [x] Integrate Dancing Rune Weapon (49028) for player and generated-companion Death Knights. Casting applies its sourced 12-second aura; the simulator does not fabricate a separate summon actor or stats. During the window, player and companion runtimes mirror eligible landed direct hostile primary-target spells and melee autos at half of the owner's raw damage. The [AzerothCore 3.3.5-derived handler](https://github.com/azerothcore/azerothcore-wotlk/blob/master/src/server/scripts/Spells/spell_dk.cpp#L3260-L3419) is the executable server reference, not a TrinityCore implementation: spell gates require a learned spell (Death Coil damage child 47632 is the exception), a living hostile target, and exclude listed utility spells (Raise Dead/Ally, Death Grip, Dark Command, Death Pact, Death and Decay, Anti-Magic Shell), positive/summoning actions, and secondary AoE targets. Companion mirroring is a simulator extension over modeled companion actions. The source Rune Weapon's independent hit/crit/stat calculations are approximated by reusing the owner's pre-target-mitigation raw damage at 50% through the existing target-damage path; periodic spell ticks and a separate Rune Weapon actor are not modeled. Coverage: 10 focused helper tests plus player Death Coil/window-expiry and companion summon-aura/Death Coil/melee integration regressions pass.
### Rogue
- [x] Improved Kick follows the requested stock effect: Kick has a 50%/100% chance to silence the target for 2 seconds. Its max-rank capstone restores up to 40 Energy and grants 35% attack speed for 6 seconds after a successful interrupt. The generated tooltip and player/party runtime use these effects; the generated movement-speed cap is ignored.
- [x] Combat Potency's local custom child 415010 confirms its rank-3 cooldown rider targets Blade Flurry (13877), Killing Spree (51690), and Combat Readiness (86378) by one second. The existing runtime applies this to those abilities when present; Combat Readiness is absent from the stock 3.3.5 generated catalog, so the custom recipient remains unavailable in this catalog scope.
### Shaman
- [x] Elemental Devastation follows generated talent node 1645: direct Fire/Frost/Nature spell criticals grant the rank's 4/8/12% melee and ranged critical chance for 10 seconds. Player and generated companion Shamans use the event path; periodic damage is excluded.
- [x] Extend Elemental Focus (`talent-574`) to generated companion Shamans: landed nonperiodic Fire/Frost/Nature spell criticals use the generated rank's 50%/100% proc chance and grant two Clearcasting charges for 15 seconds. Each committed eligible spell spends one charge and reduces mana cost by 30%. The player path already used these generated rank values; the local SpellDuration row 8 supplies the missing 15-second duration. Focused validation: 2 profile tests and 5 party Shaman tests.
- [x] Improved Shields applies the generated 5/10/15% increase to Water Shield orb mana for player and generated companion Shamans.
- [x] Implement Lightning Overload's generated base effect (`talent-1686`, rank spells 30675/30678/30679) from [the local generated 3.3.5 rank row](../src/game/wow335Talents.generated.ts#L72628): Lightning Bolt and Chain Lightning landed direct spell hits use the local 7/14/20% rank chance, tripled after a critical hit. A proc resolves a same-target echo from half the initiating spell's pre-defense amount, with no extra mana cost or threat and no recursive Overload roll. Player and generated-companion paths are covered; companion Lightning Bolt/Chain Lightning damage uses Nature school. The local source does not give a separate event rule for Chain Lightning jumps, so the simulator checks each direct target hit in its existing damage loop. Focused validation: 2 helper tests and 2 player/companion integration tests.
- [x] Implement Elemental Warding (`talent-1640`, generated spells 28996/28997/28998) from the [local generated talent node](../src/game/wow335Talents.generated.ts#L70552): ranks 1/2/3 reduce the owner’s incoming Fire, Frost, and Nature damage by 2/4/6%. The rank helper reads only that owner clause and prevents generic parsing of the separate Tethered Elemental-only riders. Both player and generated-companion incoming-hit paths apply the school-scoped modifier after existing race and Druid multipliers; Fire/Frost/Nature reductions and unchanged physical/Arcane/Holy/Shadow damage are covered. Focused validation: 6 helper tests and 7 player/companion integration tests.
- [ ] Model Elemental Warding’s separate Tethered Elemental damage reduction (5/10/15%) and threat bonus (50/100/150%) only if the simulator gains an actual Tethered Elemental actor and pet-specific incoming damage/threat. The current simulator has no such actor; do not apply these clauses to the Shaman or generic companions.
- [ ] Review the remaining passive and proc talents for event-model coverage.
- [x] Close Convection's Earthquake catalog question. Generated Shaman Convection (`talent-564`) mentions Earthquake, but local 3.3.5a `Spell.dbc` has no matching `SkillLineAbility.dbc` assignment for Earthquake and the generated class catalog has no learnable Earthquake row. The talent tooltip reference alone does not establish a Shaman ability; do not synthesize a catalog entry or mana-cost mapping.
- [x] Close the Fireball/Frostbolt attribution question. Local 3.3.5a `SkillLineAbility.dbc` assigns Fireball ranks to Mage Fire (SkillLine 8, class mask 128) and Frostbolt ranks to Mage Frost (SkillLine 6, class mask 128); neither has a Shaman assignment on SkillLines 373/374/375 (class mask 64). Their appearance in generated Maelstrom Weapon (`talent-2057`) rank text is not class-attribution evidence, so no Shaman rows or gameplay mappings are added. The class-skill-line mapping is defined in [the ability generator](../scripts/generate-wow335-abilities.mjs#L16-L23); the generated Convection node is [here](../src/game/wow335Talents.generated.ts#L70074).
- [x] Add the generated Maelstrom Weapon PvP damage rider: 2% less damage per consumed stack (10% at five stacks) for eligible damage spells against `characterDefender`; exclude Lesser Healing Wave healing and NPCs. Player and companion casts preserve the consumed stack count through cast completion and channel pulses.
- [x] Implement WoW Shaman Flurry (`talent-602`) for players and generated companions. Local generated rank descriptions supply 4/6/10% melee haste and three charges; their child aura rows resolve locally to a 15-second duration, so WotLKDB is only corroboration. The rank-two expanded tooltip says 6% while its raw child `basePoints` says 7%; runtime follows the generated tooltip. A landed direct melee critical applies the actor's rank, and each next melee autoattack attempt consumes one shared charge across both hands. Charge refresh on re-proc, equal-time hand order, and proc-phase flags are documented implementation boundaries. See [the source/runtime note](WOW_SHAMAN_FLURRY.md).
- [x] Nature's Guardian (`talent-1699`) now handles the generated 33/66/100% chance when a landed, positive, nonperiodic damaging attack takes the Shaman from at/above 30% to below 30% health. The source-backed 30-second cooldown is actor-owned; the proc arms one guaranteed critical for the next resolved Nature damage or healing spell, consumed once per spell. The self-heal amount/formula is still unknown and remains unwired. Player and generated-companion paths are covered; see [the event-model note](WOW_SHAMAN_NATURES_GUARDIAN.md).
### Paladin
- [x] Illumination (`talent-1461`) uses local generated 33/66/100% critical Flash of Light/Holy Light/Holy Shock proc chances and a 50% refund of the unmodified DBC base Mana cost. Player and companion paths snapshot that rank's base cost at cast start and restore through the normal Mana cap. WotLKDB's stock 20%/30% row conflicts; generated local data remains project authority. A separate Light's Hammer cooldown rider is unsupported because no matching local catalog row exists. Payment rank selection semantics were not changed; a level change mid-cast could still alter charged rank independently of the refund snapshot.
- [x] Vengeance (`talent-1402`) applies one stack after positive landed Paladin critical damage from a weapon swing, spell, or ability. Generated ranks define 1/2/3% per stack, five stacks, and 15 seconds; damage bonus applies to Holy damage or exact Crusader Strike/Divine Storm rows. Player and companion share the resolved-hit runtime path. Generated tooltip values intentionally supersede conflicting child Spell.dbc values (3 stacks/30 seconds, Physical+Holy).
- [ ] Resolve Vindication's capstone AP gain. Rechecked generated rank `talent-1633`/209452 and current Area-52 patch-D and client-current patch-T `Spell.dbc` rows: effect 0 is a proc-trigger aura (42) linked to AP-reduction spell 67; effects 1/2 are self-targeted aura 4 (`DUMMY`), with base 1 and +1.55/+0.90 per level, but neither specifies an AP operation or child spell. The rank text says only that AP increases after qualifying Holy damage, without a quantity. SLS row 209451 separately names flat-AP child 200067 and a Holy-damage increase; 200067's AP aura is not referenced by rank 3. Stock 3.3.5a Spell.dbc copies contain 67/9452/26016 but omit all three custom IDs. WotLKDB direct URLs for 209452, 209451, and 200067 were inaccessible on recheck, and indexed searches found no matching WotLKDB rows. Keep the gain unwired: the DUMMY coefficients and separate SLS child do not establish 209452's AP formula or operation.
- [x] Aura Mastery follows the current talent tooltip and [WotLKDB 3.3.5a spell 31821](https://wotlkdb.com/?spell=31821): 6 seconds, not the conflicting older generated class row's 10 seconds. Its tooltip/behavior includes 50% self-only duration reduction for represented confuse/fear/sleep controls, silence/interrupt immunity for affected allies, and doubled modeled modifiers from the same Paladin's aura; Retribution Aura's generated rank damage is Holy and doubled while Aura Mastery is active. Party incoming-hit retaliation is wired, including the DBC's +0.033 spell-power coefficient for player and companion Paladins. Concentration Aura pushback reduction is now integrated on player and generated-companion incoming cast/channel paths: its exact aura plus Paladin source supplies 35% base, and that Paladin's Improved Concentration Aura ranks add +7/14/20 percentage points. This scales the existing 500ms cast and 25% channel penalties after the cast's pushback-resist check; two-hit limits and spell-specific resistance remain intact. Aura Mastery does not amplify this separate modifier. Stock WotLKDB ranks (+5/10/15) are not used.
### Mage
- [x] Frost Warding Ward proc (`talent-70`) supports the local Mage Fire Ward and Frost Ward rows for player and companion incoming matching-school spell damage: generated ranks set 25/50% proc chance, 50% damage reduction, and Mana refund equal to damage reduced. The simulator applies reduction before ordinary Ward absorption as an explicit ordering inference because generated tooltip text does not specify it; stock full-absorb behavior is not imported. Arcane Ward has no local Mage row; Shadow Ward is Warlock, so neither is synthesized.
- [x] Frost Warding armor rider (`talent-70`) scales only the positive armor/resistance modifiers on the exact local Mage Frost Armor or Ice Armor cast-generated aura by the generated 25/50% talent rank. Player and companion auras carry the modifier for their own duration and exclusive armor replacement; no aura means no bonus, and generic talent parsing remains guarded.
- [x] Netherwind Presence (`talent-1846`) uses the generated local 1/2/3% spell-haste-per-stack ranks, three-stack cap, and 10-second refresh. Accepted casts of the generated Mage trigger spells grant one stack per cast; cast-commit timing is an explicit inference because generated proc-phase flags are absent. At max rank, Slow at three stacks grants 30% movement speed for three seconds and preserves the haste stacks. Player and companion cast timing plus player/companion movement paths are wired; Arcane Orb is absent from the Mage catalog, and Moonfire/Starfire/Starsurge are not Mage entries, so those tooltip triggers remain unavailable. No WotLKDB fallback was used because stock 44400 describes a different permanent 2% talent. Focused validation passed 7 tests across two files; see [the feature note](WOW_MAGE_NETHERWIND_PRESENCE.md).
- [x] Focus Magic follows generated talent node 2211: its recipient aura and tooltip use +1% spell critical chance, while the separate Mage proc remains +3% for 10 seconds. The older `patch-enUS.MPQ` class spell row 54646's +3% recipient value is superseded by the current generated Area-52 talent data.
- [x] Improved Fire Blast (talent-27) reduces Fire Blast's cooldown by 1/2 seconds and increases its damage against monsters by 5/10% for players and generated companions; explicit rank modifiers prevent mixed-unit tooltip parsing from inventing values.
- [x] Shatter (talent-67) adds the generated +17/34/50 percentage points of critical chance to nonperiodic Mage spell hits against frozen targets, including Fingers of Frost, for players and generated companions.
- [x] Verified generated Mage talent-tooltip references against local `patch-enUS.MPQ` 3.3.5a Spell.dbc and SkillLineAbility.dbc: Moonfire and Starfire ranks map to Druid (skill line 574, class mask 1024); Arcane Orb rows 34172/34190 have no player skill-line or talent mapping; Frozen Orb and Starsurge have no named rows in this local Spell.dbc. WotLKDB's Frozen Orb row 72082 has no Mage class/trainer attribution, so tooltip mentions alone do not justify adding/remapping these entries.
### Warlock
- [x] Wire player Aftermath ranks 18119/18120 to proc on landed Conflagrate for 50%/100%, applying the generated talent tooltip's 50% slow for 4 seconds. Per the project source preference, the generated custom tooltip takes precedence over stock child 18118's WotLKDB 70%/5-second payload.
- [x] Add Aftermath to generated companion Warlocks: landed direct primary-target Conflagrate uses generated talent-982 ranks, a deterministic companion-seeded 50%/100% proc, and the same generated-tooltip 50% slow for four seconds as the player path. Companion Conflagrate now derives its burst from that Warlock's active Immolate/Shadowflame and consumes the DoT only after the hit lands. Party regression covers ranks 0 and 2, exact burst amount, and DoT consumption.
- [ ] Resolve Soul Leech (talent-1678)'s +30% critical-chance rider after a physical hit while casting. Unlinked custom patch-D rows 830297–830299 hint at a one-charge current-cast buff and cast-finish cleanup, but no rank spell links to them; neither the trigger, rank gate, nor consumption behavior is established. Keep the rider unwired until a matching source connects those rows.
- [x] Adopt current CoA Mind Transference (Warlock/Warrior 498642): spend 75 Rage, grant 6 Psi, and use a 1-second cooldown. The [current pair page](https://chroniclesofarcadia.com/en/wiki/skills/list/9-1), [10.2.1 patch](https://chroniclesofarcadia.com/patch/10-2-1-1000) (fixed 50 Rage → 6 Psi), and [11.1.2 patch](https://chroniclesofarcadia.com/patch/11-1-2-1000) (75 Rage, 1-second cooldown) establish the current conversion. This replaces the local RuneWaker tooltip's consume-all-Rage, 35-Rage-per-Psi rule. Local component 621320 also grants +40% physical attack for 30 seconds; current CoA does not confirm that rider, so it is intentionally omitted. Player and companion conversions have focused regression coverage.
- [x] Adopt current CoA Enraged 499871 from the [Warlock/Warrior page](https://chroniclesofarcadia.com/en/wiki/skills/list/9-1): Warrior General level 60, instant, 40-second cooldown, restores 100 Rage, 35 Focus, and 1 Psi. Add it as a separate Warlock/Warrior learned row, preserving RuneWaker Warrior General Enraged 490492. Local 499869 is a learned level-70 Warlock/Warrior Mind Transference row (key 546844, prerequisite 499868, slot 25), not current-CoA Psychic Warrior or Enraged; its Rage-to-Soul-Point conversion is RuneWaker-only. See [the local source follow-up](ROM_WARLOCK_SOURCE_FOLLOWUP_2026-10-02.md). The shared resource-effect path handles all three pools for player and companion; regressions cover level-60 learnability, exact pair gating, resource caps, and cooldown.
- [x] Replace local Divine Assistance (Warlock/Priest 498668)'s Inspiration-stack/Defense Net reset behavior with the current passive +16% Magical Damage and Healing. The [10.2.1 patch](https://chroniclesofarcadia.com/patch/10-2-1-1000) establishes the stat effect and [12.1.0](https://chroniclesofarcadia.com/patch/12-1-0-5000) makes it passive; the [current pair page](https://chroniclesofarcadia.com/en/wiki/skills/list/9-5) confirms the current payload. Player and companion effects are covered.
- [x] Update Warlock/Priest Healing Fortune (498633): a landed Psychic Arrows hit grants +12% heal power and +12% Wisdom for 20 seconds, and Warp Charge heals a friendly target instead of dealing damage. Psychic Rising Tide (498643) makes Rising Tide instant with a 5-second cooldown, restores 1 Psi, and triggers Healing Fortune on a critical hit. The [current pair page](https://chroniclesofarcadia.com/en/wiki/skills/list/9-5) selects these current effects over RuneWaker's instant/free Urgent Heal proc descriptions. The simulator cannot route an ally-targeted Rising Tide cast to that ally's hostile target because party members have no hostile-target selection state; the current passive's other sourced effects are wired.
- [x] Replace RuneWaker's stale Warlock/Priest Soul Enlightenment (498649) payload with current CoA's +5.7% damage dealt and +17.1% received healing for 30 seconds, costing 2 Psi, in a 7.5-unit party aura radius (CoA range 100/radius 75 interpreted through the established 10:1 conversion). Exact-pair catalog and player/companion cast integrations are covered. The simulator has only a party roster, and its existing area targeting requires line of sight. CoA's Willpower Construct Caster-only restriction is retained in the tooltip but not enforced because the cast validator has no corresponding state gate. See [the source/rationale note](ROM_WARLOCK_PRIEST_SOUL_ENLIGHTENMENT.md).
- [x] Integrate current CoA Ring of Comfort (Warlock/Priest 498641): an accepted exact-pair cast grants 1 Psi to the caster, not each healing recipient; player and generated-companion tests cover recipient scope and caps. The CoA row does not name the recipient, so caster-scoping is an explicit interpretation. The separate Mind Shield reset chance stays open.
- [x] Add Mind Shield's (Warlock/Priest 498648) explicit +1 Psi on Urgent Heal from the [current pair page](https://chroniclesofarcadia.com/en/wiki/skills/list/9-5). Its Defense Net duration reduction is retained. Keep current CoA's Ring of Comfort reset chance open because the proc probability is unspecified, and leave the enhanced-defense amount unmodeled because CoA does not quantify it. The separate local RuneWaker Mind Shield check is Rand 100 gated on learning 498648 and its RunPlot resets Ring on HIT/CRITICAL Urgent Heal; do not transfer that guaranteed local result into CoA mode. See [the local source follow-up](ROM_WARLOCK_SOURCE_FOLLOWUP_2026-10-02.md).
- [x] Integrate current CoA Warlock/Priest Spreading Pain (499856) in the generated catalog/tooltip and player/companion cast effects. The [current CoA pair page](https://chroniclesofarcadia.com/en/wiki/skills/list/9-5) specifies the three linked debuffs, +18% Magical Attack Power, +25% Magical Critical Bonus, and activation of Healing Fortune. Patch [10.6.1](https://chroniclesofarcadia.com/en/patch/10-6-1-1000) narrows that activation to Healing Fortune's +12% healing for 20 seconds, excluding its Wisdom and Warp Charge clauses. The three RuneWaker children 497959/497960/497964 remain intact. The tagged +25% Magical Critical Bonus aura is consumed by the central critical resolver for player and companion magical spell crits, scaling only the bonus portion (2.0 becomes 2.25); crit chance and ordinary hits stay unchanged. CoA lists 10% MP plus 15 Focus and range 150, while the local row supplies only 15 Focus and range 22.5. RoM Warlock has no Mana pool and no general CoA range conversion is established; keep the unrepresentable base-MP difference and local range documented rather than inventing a cost/range override.
- [x] Complete Warlock/Mage Soul Brand (498705) player and party event hooks. Current CoA replaces RuneWaker's three-skill trigger and 9% Dark/Flame-only debuff with a +2% per stack (four-stack cap, 20-second refresh) damage-taken aura from any landed Fire damage, including periodic hits, plus 1 Psi per trigger. Player and generated-companion direct/periodic event paths apply the target aura and grant Psi to the triggering source. The simulator maps the five RoM elemental categories to Fire, Frost, Nature, Holy, and Shadow; Physical and Arcane are unaffected.
- [x] Implement current CoA Warlock/Mage Soul Brand Sting (498710): 2 Psi, 1× derived Intelligence added to each 3737.5 Dark/Fire packet, cast only under an active locally tagged Willpower Blade aura, and reset Flaming Heart Strike on cast. The CoA state entry is ID 1494096 and the local RuneWaker aura source is ID 497955; the gate uses the observed local state name and does not equate those IDs. Preserve local range 22.5 because CoA's 150 has no verified unit conversion. See [the source/rationale note](ROM_WARLOCK_MAGE_SOUL_BRAND_STING.md).
### Druid
- [x] Companion Rejuvenation snapshots the owner's Improved Rejuvenation rank bonus (+7/14/20%) when the HoT is applied, matching the player healing path.
- [x] Nature's Reach (talent-764) adds the generated +2/4/6 yards to cast-time/channel damaging spells for players and generated companions; instant damage and healing spells receive no range bonus.
- [x] Master Shapeshifter (talent-1915) applies the generated rank 2/4% form-specific bonus to Bear physical damage, Cat melee critical chance, Moonkin Arcane/Nature damage, and Tree healing across player and companion direct/periodic paths.
- [x] Predatory Instincts (talent-1795; rank spells 33859/33866/33867) applies Aura 163's 5/10/15% increase to the critical bonus portion and Aura 229's 4/7/10% reduction to damage from authored area attacks, with both clauses gated by Cat Form. Generated rank text and local DBC effects give the values; [WotLKDB rank 2](https://wotlkdb.com/?spell=33866) independently confirms Cat Form plus Aura 163/229. Player and generated-companion outgoing/incoming paths are covered. The general `damagePlayer(amount, school)` adapter has no attack-delivery metadata, so this AoE-specific rider is applied only when the enemy attack definition identifies `delivery: "area"`; no competing AoE-specific reduction is currently modeled, and the source's non-stacking clause is therefore not independently exercised.
- [x] Catalog attribution check: Lesser Healing Wave is present only as a Shaman spell in the stock 3.3.5 data; Flourish is in the separate custom Ascension class-11 catalog, not the stock Druid catalog. Neither should be added to the stock Druid catalog from a tooltip reference alone.
### Warrior
- [x] Damage Shield reflects 10/20% of resolved block value after a landed direct melee hit for players and generated companions.
- [x] Resolve Unbridled Wrath's project data choice: use generated node `talent-159`'s custom 2/4-Rage tooltip values, with the upstream [WotLK Simulator](https://github.com/wowsims/wotlk/blob/master/sim/warrior/talents.go)'s 3 procs-per-minute-per-rank melee-white-hit model to fill the missing effective proc rate. The generated child links still conflict (12964/812964), but the project's generated tooltip takes precedence; an isolated calculation helper is in place.
- [x] Unbridled Wrath grants the generated 2/4 Rage on eligible landed, damaging Warrior main-hand melee autoattacks, using the source-backed 3 procs-per-minute-per-rank rate and each Warrior's un-hasted weapon speed. Player and generated-companion hits are covered; Warrior off-hand autoattacks are not modeled.
- [x] Improved Victory Rush uses generated 33/66/100% parry proc ranks, a 10-second ready window, 12-second internal cooldown, +20/40/60 percentage points of Victory Rush critical chance, and +33/66/100% threat during the parry window. The base Victory Rush ability is also enabled for 20 seconds after an XP-yielding kill. Player and generated companion casts are gated on readiness and consume the landed-hit window.
- [x] Critical Block (`talent-1893`) applies its generated 8/16/25% extra reduction to successful blocked hits for player and generated-companion Warriors. The reduction is excluded against player attackers and when Touched by the Light (`talent-2195`) is learned; the conflicting stock double-block chance is not applied.
- [x] Improved Defensive Stance applies its generated stance mitigation and avoidance-triggered Enrage proc for player and generated-companion Warriors.
## RuneWaker
### Warrior
- [x] Add current CoA's missing level-50 Warrior/Knight Blocking Stance passive (493287) as a distinct catalog marker. The [current CoA pair page](https://chroniclesofarcadia.com/wiki/skills/list/1-6?locale=en) lists it separately from Resist (493251) and local active Blocking Stance (491480). Its tooltip records the sourced stance-gated static modifiers; the marker carries no generic stat aura so the bonuses do not activate when 491480 is off. Its physical-hit proc grants 3 Rage with a 10-second retrigger lockout, but the chance is not stated.
- [x] Integrate current CoA's Warrior/Knight stance modifiers: learned Blocking Stance 493287 plus active local stance 491480 gives +8% parry, −18.9% received damage, and +75.4% Aggro; learned Resist 493251 gives +80% Aggro and 20% reduced received Physical Damage. Player and generated-companion incoming hits and threat use the sourced factors. The two Aggro bonuses remain separate and their combined result is neutral/unmodeled until CoA stacking is established; the Rage proc chances are unspecified, so they remain unmodeled. CoA lists a 10-second retrigger lockout for each proc.
- [x] Finish current CoA Warrior/Rogue Exhaustion (493248). The [current CoA Warrior/Rogue page](https://chroniclesofarcadia.com/en/wiki/skills/list/1-3) confirms the same name, ID, and pair as the local passive; it reduces Whirlwind's Rage cost by 20 and cooldown by 10 seconds, and a landed Probing Attack has a 30% chance to restore 25 Energy and 50 Rage. Player and generated-companion landed-hit hooks use that proc; focused coverage checks player casts and the capped companion resource helper. The separate CoA Probing Attack 493283 uses a 664.3% main-hand DPS coefficient, or 1116.9% with a caster-owned Bleed or locally represented two-handed hammer (`mace` in weapon metadata). The unquantified hammer cooldown rider remains unapplied. The local primary-Warrior Probing Attack 491133 remains distinct and does not trigger Exhaustion. The earlier ID-move claim was incorrect: the current CoA page still identifies Exhaustion as 493248 and Morale Slash as 1491760.
- [x] Apply the supported Warrior/Druid Recovery of Life (494377) → current CoA Rage of Calmness changes. The [CoA Warrior/Druid page](https://chroniclesofarcadia.com/en/wiki/skills/list/1-8) confirms the same passive ID/name lineage and says Whirlwind costs less Rage and has a shorter cooldown. Local RuneWaker 494377 supplies −10 Rage and −10 seconds for Whirlwind, while component 506368 gives the post-hit general Rage rider a 20-second window. CoA's current page references Whirlwind 494939, while the RuneWaker catalog exposes 490133; `romWarriorDruidRageOfCalmness.ts` gates the local values to learned 494377 on Warrior/Druid and local Whirlwind 490133. Player and companion cost/cooldown paths and the catalog label are updated. Focused helper and player/party integration coverage passes 8 tests across two files.
- [ ] Implement Rage of Calmness's post-hit general Rage-cost reduction only when its numeric amount is sourced. The 20-second duration is known from local component 506368, but neither that component nor current CoA specifies the reduction amount; the rider remains explicitly unwired.
- [x] Warrior/Warlock Speed Slash (499827): runtime applies the current CoA −10 Rage cost to Slash, and its generated tooltip now says Slash damage increases without inventing the unspecified amount. The [current CoA pair page](https://chroniclesofarcadia.com/en/wiki/skills/list/1-9) does not support RuneWaker's missing-child cooldown reset.
- [x] Warrior/Warlock Excellent Combat Training (499806): runtime applies current CoA's +20% Physical Damage from the [current CoA pair page](https://chroniclesofarcadia.com/en/wiki/skills/list/1-9), and its generated tooltip now states that effect without unsupported cooldown resets.
### Scout
- [x] Scout/Knight Enhanced Armor Perfection (492346) uses local component 501823 to extend Enhanced Armor (490152) from its 300-second base to 600 seconds for player and party casts.
- [x] Scout/Priest Sniper (492344) reduces Snipe (490450)'s cast time by one second for player and generated companion Scouts.
- [x] Scout/Priest Screen Attack (499555) now follows current CoA's active +17.4% party damage buff for 20 seconds and 60-second cooldown, replacing the local passive marker. CoA lists +55 skill training (not character level) and radius 150; the simulator has no training rank and interprets radius as 15 project units. Current skill-page duration wins over patch 11.1.1's earlier 30 seconds; DoT coverage follows the patch. Player and generated-companion casts scale direct and periodic damage, use existing party radius/LOS/living-recipient rules, and expire at the modeled 20-second boundary. See [the source/runtime note](ROM_SCOUT_PRIEST_SCREEN_ATTACK.md).
- [x] Keep Scout/Mage Wind Return (499548), Scout/Priest Revival Engraving (499552), and Scout/Warden Forest Guidance (499575) as learned-only markers. This prevents generated child components from being misapplied as owner auras; their active trigger rows or pet-target behavior remain unsupported. The exact-pair overrides do not create triggers or infer pet stats. See [the source audit](ROM_SCOUT_REMAINING_PASSIVES_AUDIT.md).
- [x] Scout/Priest Drums of War (493010) follows CoA's +20% critical damage after landed Shot (CoA Shot 493011 is mapped by name/role to local RuneWaker Shot 490423). It lasts 15 seconds and then waits another 15 seconds before it can proc again, interpreted as 30 seconds from proc to ready. The buff applies to party members within the modeled range 50; it raises the critical bonus portion (2.0→2.2), leaves chance/noncrit damage unchanged, and stacks additively with critical-damage bonuses such as Spreading Pain. Player/companion proc and hit-resolution tests are documented in [the source/runtime note](ROM_SCOUT_PRIEST_DRUMS_OF_WAR.md).
- [x] Priest/Scout Curing Shot (492636) now follows current CoA: instant, 6-second cooldown, 125.6 immediate healing, then 167.5 every 3 seconds for 18 seconds, radius 100 (10 project units), no target cap, and caster-only +10% Elemental Damage for 18 seconds. CoA says all raid members; the simulator reaches all eligible modeled party members. CoA defines Elemental Damage by subclass; Water is inferred from the Priest/Scout kit and maps to the project's `frost` school, so other schools are unchanged. The local 120 MP cost is preserved because CoA publishes 242 MP only at +105 without a cost curve. Player/companion coverage and source assumptions are in [the feature note](ROM_PRIEST_SCOUT_CURING_SHOT.md).
- [ ] Quantify Scout/Warrior Enhanced Throat Attack (491489)'s extra range. Hash-matched RuneWaker data has no components or modifier linking it to Throat Attack (490428); the passive's own range 5 is its cast-distance field, not a range bonus. The current [CoA patch notes](https://chroniclesofarcadia.com/patch/11-1-1-4000) rework the same-named skill into Soldier's Determination, so that later behavior does not fill the RuneWaker amount. Do not apply the cast-distance field as an additive modifier.
- [x] Model RuneWaker item 200563, Poison Powder, as an unlimited carried reagent for Scout/Rogue. Poisonous Spit does not require the separate Rogue Poison Bottle aura.
- [ ] Add pet-specific stats and event hooks before implementing pet critical, dodge, and damage passives.
- [ ] Review the remaining Scout paired-class passives for source-backed runtime coverage.
### Rogue
- [x] Align Rogue/Scout Coerce (493019) to current CoA's [+20.2% Low Blow damage](https://chroniclesofarcadia.com/en/wiki/skills/list/3-2). CoA says the ability also lowers Energy cost but omits the amount, so retain only the compatible local −5 Energy reduction; remove RuneWaker's conflicting below-30%-health temporary +2% Physical Damage proc. Player and generated-companion Low Blow paths are covered.
- [x] Follow current CoA Rogue-primary behavior for Poisonous Hands (490329) and Energized Hands (490347): mutually exclusive 900-second buffs; a target debuff that stacks to ten but applies a fixed 8% damage-dealt reduction total; one 1% self attack-speed stack per successful target application; and Energized Hands' +100% Energy recovery, +50% maximum Energy, +20% Energy costs, and −0.1-second skill cooldowns. CoA leaves Poisonous Hands' chance qualitative, so the populated RuneWaker 50% remains a documented fallback. Poison Bottle consumption and the faster-main-hand cast-time formula are not modeled because CoA provides no runtime inventory model or formula. The cooldown rider is applied once as a flat 100 ms at cooldown commit. Player and companion mechanics pass 49 focused tests; see [the behavior rationale](ROM_ROGUE_POISONOUS_HANDS.md).
- [x] Replace Rogue/Mage RuneWaker Enchanted Throw with current CoA Chaos Dagger (491178): the learned passive adds a Fire packet equal to 169.4% of the attacking hand's weapon DPS on each landed main-hand or off-hand normal attack for players and generated companions. The matching CoA skill page and [12.1.0.4000 patch](https://chroniclesofarcadia.com/patch/12-1-0-4000) establish the current passive identity and damage; RuneWaker's 25-Mana activatable projectile buff, Throw substitution, and hidden physical child 491185 do not describe the current skill and are removed for this pair. The current page still lists 25 MP but does not say whether it is paid per normal attack after the passive conversion; runtime does not invent that recurring debit. The slight temporary Physical Attack Power rider has no sourced amount or duration and remains unwired. See [the source and runtime note](ROM_ROGUE_MAGE_CHAOS_DAGGER.md).
- [ ] Add projectile-ammunition state if ammunition costs or consumption should affect Rogue ranged abilities.
### Priest
- [x] Priest/Warrior Condensed Rage (493038) follows current CoA as a passive +22% Physical Damage effect. The [CoA skill entry](https://chroniclesofarcadia.com/en/wiki/skills/list/5-1) confirms the same name, ID, and pair; patch 11.1.1 changed its damage type from Water/Light to Physical, and patch 11.1.1.5000 removed the buff requirement. RuneWaker's incoming-hit heal state and missing children 493056/495293 are superseded. The player and companion physical-damage paths use the learned passive without an obsolete trigger/stance gate.
- [x] Priest/Champion 498610 follows current CoA's Rage Control passive: the [current CoA Priest/Champion list](https://chroniclesofarcadia.com/en/wiki/skills/list/5-10) keeps the same ID and pair but renames/reworks RuneWaker's Infused Light Chain into a passive that grants 20 Rage for each completed second of spell channeling. Player and companion channels grant whole seconds only; ordinary casts and partial seconds do not count. Interrupted channels preserve only their completed seconds. The local Chain of Light damage, cooldown, and on-hit riders are removed.
- [x] Scope Priest/Champion Protection Rune Seal (498613) cooldown reset to positive periodic healing events from Regenerate (490269), the exact learned passive/pair, and the aura owner. The local generated 8% chance remains the numeric fallback because current CoA says only “slight chance.” Player and generated-companion paths reset only their own learned Heart Rune Energy (498612) cooldown; companion cooldown state is synchronized so healing updates cannot restore a stale value. A possible healing-strength rider has no local component/amount and remains open.
- [x] Integrate current CoA Priest/Champion Beacon of Regeneration (498620): a 30-second mark on one friendly party member, once per direct healing cast after recipients are aggregated. The [CoA row](https://chroniclesofarcadia.com/en/wiki/skills/list/5-10) publishes 770 HP at skill +105, which the simulator deliberately applies to every unlocked rank because no skill progression model exists. Player and companion casts use generic source healing-done and target healing-taken modifiers consistently; unbuffed transfer is 770 and the +5% Faith aura resolves it to 809 on either path. The local level-50 row costs 29 MP plus 1% and lists range 20 (decimeters), while CoA +105 lists 88 MP plus 1% and range 200; there is no source-backed cost curve to reconcile the flat-MP difference. Local child 621227 (`dotBase=35`, `fixedValue=0.2`, `skillLevelArg=30`) does not map to the current trigger/amount. HoT ticks and channel pulses remain excluded because CoA does not settle their eligibility and the structured event lacks a periodic marker.
- [x] Finish the CoA-backed Priest reworks mapped from local Ice Fog ranks: patch 10.2.1 explicitly maps Ice Fog 1/2/3 to Holy Blessing, Vow of Silence, and Holy Void, and the [current Priest skill list](https://chroniclesofarcadia.com/wiki/skills/list/5-1) confirms the same IDs and levels. Bone Chill is a separate skill, 491165.
- [x] Holy Blessing (490274) follows the [current CoA Priest-primary entry](https://chroniclesofarcadia.com/en/wiki/skills/list/5-7): permanent Wisdom `(current Wisdom + 115) × 1.105` and +100.9% Light damage. The tagged caster aura maps Light to Holy; player spell damage resolves its school-scoped aura, and generated-companion direct damage uses the same scope when it takes the deterministic party path. The dedicated stat stage resolves existing Wisdom modifiers first and adds only the incremental Wisdom-to-spell-power conversion to coefficient-based spell amounts; generic spell-power aura modifiers stay on their usual path. Current CoA does not specify how this formula stacks with other Wisdom buffs, so existing Wisdom modifiers use the simulator's current stat resolver before this passive is applied. `applyAuraStats` can expose the changed Wisdom and derived spell power, but cast coefficients read equipment scaling directly; the per-skill delta bridges that boundary without double-counting generic spell-power fields. Player and generated-companion combat tests cover actual spell amounts and Holy versus Nature damage. The player Frost control includes RuneWaker's existing “Prayer: water-damage” +5% Frost aura in its expected value; the Holy and Nature controls isolate Holy Blessing's school scope.
- [x] Vow of Silence (490275) interrupts and silences for 8.4 seconds on NPC targets and 4.2 seconds on player targets. Player and generated-companion casts use the shorter player-target duration.
- [x] Holy Void (490276) follows the current [CoA Priest-primary entry](https://chroniclesofarcadia.com/wiki/skills/list/5-1): instant 1655 Light damage plus Voidal Infection for 20 seconds, reducing physical and magical defense by 18.8%. The cast override maps the catalog's physical-defense alias to armor and keeps the magical-defense debuff; player and generated-companion casts against NPCs both deal Holy/Light damage and apply the target aura. NPC armor and modeled magical resistances are reduced by the debuff. The generic aura path supports character targets, but this focused test covers NPC targets only. NPCs have no Light/Holy resistance field, so magical-defense does not mitigate Holy Void's Light hit; this remains an explicit simulator limit. Three focused runtime regressions pass.
- [x] Finish Priest/Champion Heart Rune Energy (498612)'s current CoA behavior. The [current CoA Priest/Champion entry](https://chroniclesofarcadia.com/en/wiki/skills/list/5-10) and patch [11.1.5.3000](https://chroniclesofarcadia.com/tr/patch/11-1-5-3000) confirm the same name, ID, and pair, but a deliberate payload rework: replace local healing and +2% Mind with 975.1% CPS Light damage (runtime coefficient 9.751, Light/Holy school), 15 Rage cost, 150 range, 80 radius, instant cast, 12-second cooldown, and −15 seconds to Blessing of Humility's cooldown on use. Patch [11.1.5.4002](https://chroniclesofarcadia.com/patch/11-1-5-4000) confirms the AoE is centered around the caster with 80 range. Player and generated-companion regressions confirm damage to targets at or inside 80, none just outside, six eligible targets without a catalogued cap, Rage cost, cooldown, and Blessing cooldown reduction. CoA publishes no target-count cap, so none is added; the simulator resolves targets among its modeled visible/engaged mobs. The existing Protection Rune Seal test still verifies its separate Regenerate tick reset against ID 498612.
- [x] Rework Priest/Mage Enlightenment (492933) to current CoA. The [current CoA Priest/Mage page](https://chroniclesofarcadia.com/fr/wiki/skills/list/5-4) confirms the same name, ID, and pair, and says it passively increases Wisdom by 12%. This replaces RuneWaker's completed-Heal (490261) trigger, +1% Wisdom for 8 seconds, and 20-second internal cooldown. The catalog tooltip now reads “Passive: Increases Wisdom by 12%,” and the effect is a permanent caster aura with a standard Wisdom percent modifier of 0.12. Player passive synchronization activates it when the build is initialized or updated; generated companions apply learned self-target passives before their first RuneWaker cast. Two helper tests and two player/companion integration tests pass. No special formula or runtime limitation is known for this modeled stat modifier.
- [x] Integrate current CoA Priest/Scout Saint's Blessing (493039): the current skill page gives +28% damage only against live targets below 30% max HP, separately from its low-health Heal rider. Player and generated-companion direct and periodic damage packets check the live target threshold at each packet and apply +28% once. The older 11.1.5.2000 patch says +21%; the current +28% row takes precedence. The separate Heal rider is documented but still unresolved: CoA lists Heal 493048 with +597/+21% at skill level 105, while the local generated catalog has no 493048 row or current lower-rank curve. See [the source/runtime note](ROM_PRIEST_SCOUT_SAINTS_BLESSING.md).
- [ ] Review the remaining conditional Priest passives for complete source-backed triggers and effects.
### Knight
- [x] Knight/Rogue Panther's Blessing (493047) follows the same-name current CoA passive and restores 10% maximum HP and 1% maximum Mana on a resolved incoming dodge. The simulator uses maximum-pool bases and whole-point rounding because CoA does not specify percentage bases or rounding. The legacy RuneWaker +2 Dodge child is suppressed; this is not God's Vengeance, which is passive 499934.
- [x] Remove legacy Holy Seal periodic damage from 490148, 490149, 490150, and 490151 while preserving their direct attacks and seal build/spend behavior. Current CoA Knight/Warrior entries and patch 10.6.1 establish that Holy Seal no longer deals periodic damage; the runtime filters only those legacy DoT outputs.
- [x] Align Knight-primary Holy Power Explosion (490172) to current CoA's passive +198% Aggro. The [current CoA Knight/Warrior page](https://chroniclesofarcadia.com/wiki/skills/list/6-1?locale=en) identifies the passive; patch [12.1.3](https://chroniclesofarcadia.com/patch/12-1-3-1000) confirms the value. The old active mana/healing payload is removed. Knight, Blocking Stance, and Resist threat factors are applied individually when their source gates are met; overlapping Aggro factors remain uncombined pending a source-defined stacking rule.
- [x] Replace the stale Knight/Rogue Leopard Instinct (495402) absorb with CoA's current passive stacks: each received hit adds one stack, up to 10, granting +3 percentage points Dodge and a separately recorded +3% Magic Resistance Rate per stack; a dodge removes one stack. Player and companion incoming-hit/dodge paths update the stack aura. Patch [11.1.5.3000](https://chroniclesofarcadia.com/tr/patch/11-1-5-3000) replaced the absorb, and patch [12.1.2](https://chroniclesofarcadia.com/fr/patch/12-1-2-1000) made it passive. Magic Resistance Rate remains unapplied because the simulator has no consumer; no absorb or timer is substituted.
- [x] Fearless (490088) preserves its local +3% Strength and +3% Stamina effects and grants 20-second Fear immunity; the misleading Fear-control tooltip marker is filtered out.
- [x] Integrate current CoA Knight/Rogue God's Sword (491621): while the level-15 passive is learned, offensive physical abilities add 350% of offhand weapon DPS as Light damage and generate high Aggro. The current [CoA skill entry](https://chroniclesofarcadia.com/wiki/skills/list/6-3?locale=ru) confirms the same ID/name/pair; patch [10.6.1](https://chroniclesofarcadia.com/en/patch/10-6-1-1000) begins the offhand-DPS rework, [11.1.5](https://chroniclesofarcadia.com/tr/patch/11-1-5-3000) changes it to 350% Light, and [12.1.0](https://chroniclesofarcadia.com/patch/12-1-0-5000) makes it passive. This supersedes RuneWaker's +40% Holy Strike crit rider. Player and generated-companion landed direct-hit resolvers now check the Knight/Rogue pairing, learned passive, a qualifying physical ability (including source descriptions marked “Physical Light Damage”), and positive offhand DPS, then record a separate Light/Holy damage packet at 3.5× offhand DPS. Validation: 4 helper tests and 3 player/companion runtime integration tests passed. CoA does not publish an Aggro multiplier or specify how multi-hit, channel, and AoE casts generate extra damage; no Aggro multiplier or additional cadence is inferred, and coverage follows only the direct damage event granularity the runtime exposes.
- [x] Align Deadly Whirlwind (491639) to current CoA: successful Whirlwind hits apply Deadly Wound, with current Whirlwind text specifying 30% reduced received healing for 10 seconds (5 seconds on player targets). CoA still says the passive reduces Whirlwind Rage cost and cooldown but gives no amounts, so retain the matching local RuneWaker −10 Rage/−20-second values; do not import a damage-type or visual rider.
- [x] Bridge the local Knight/Priest 491635 row to current CoA's Compassion of Holy Light behavior. The selected English [CoA skill list](https://chroniclesofarcadia.com/wiki/skills/list/6-5?locale=en) reports Knight/Shaman, while localized/index results disagree on the displayed pair; this simulator has no playable Shaman class/pair. The code keeps the local pairing and labels the exact-ID cross-pair bridge in the tooltip; it does not claim the pair identities match. The [11.1.5 patch](https://chroniclesofarcadia.com/patch/11-1-5-3000) supplies the 120 + 0.2 × STA landed-hit heal, Holy Illumination trigger, and 5-to-4-second cooldown reduction; player and companion Whirlwind Shield hits are covered. Holy Illumination uses the current 15% damage-reduction/10-second payload. The simulator has no shield-defense stat, so the patch's 5× shield-defense damage rider is not modeled.
- [x] Align Divine Punishment (491608) to current CoA: Punishment gains 28.5% damage and applies +2% general damage taken per pre-spend Holy Seal stack for 10 seconds. This replaces RuneWaker's +1% Light-only vulnerability. The catalog assertion now passes; see [the Knight source audit](ROM_KNIGHT_REMAINING_REFERENCES_AUDIT.md).
- [x] Implement Knight/Rogue God's Vengeance 499934 through its separately learned level-50 Punishment child 499909. The child spends its own target's Seals normally; a landed hit at exactly four stacks resets only the caster's learned Shadow Step 490344. General Punishment 490151 remains separate.
- [ ] Identify unresolved periodic or triggered spell references before implementing their effects.
### Warden
- [x] Damage Transfer (493399) now handles player and generated-party Warden incoming hits. The hash-matched RuneWaker executable modifier 503942 applies a 30% transfer for 10 seconds when the owner's supported summon (102297/102324/102325) is alive and within inclusive 3D range 300; the party path applies the split once, consumes pet absorbs, syncs pet health/aura state, and records one pet damage event without chaining. Tooltip component 503643's 15-second value is not executable; do not copy later CoA behavior.
- [x] Implement the source-backed RuneWaker Rogue/Warden Revival (499542/499544) state chain for players and generated companions. Learned 499544 arms its actor-owned 900-second state; while active, only a normal, noncritical hit with positive post-absorb HP loss that leaves the owner alive adds that actor's 623072 charge (15 seconds, maximum ten) and applies component 623527's six-second +20 physical-dodge-rate aura. The 499542 heal is `maxHP × (10 + 5 × charges)%`, normal/noncritical FixPer; it does not use weapon damage, attack speed, MagicPow, or critical power. The direct `damagePlayer` adapter has no outcome payload, so positive post-absorb loss is treated as a normal hit there; authored mob/party events retain the explicit normal-hit gate. The separate 620302 HolyHeal and type-200 magical-dodge riders remain unwired because the complete native HolyHeal resolver and magical-dodge combat consumer are not modeled. Native MND/MPow/heal-rate input channels are now available for explicitly native characters; that does not implement this rider. Current CoA's reused 499542 is a different Rogue/Warden Low Blow and is not mapped onto this local ability. See [the state-chain source audit](ROM_WARDEN_REVIVAL_STATE_AUDIT.md) and [the broader source audit](ROM_WARDEN_REMAINING_MECHANICS_AUDIT.md).
- [ ] Keep the local Weak Point Strike (494043) bonus hit disabled until its proc chance is sourced; components 620294/620295 contain the two damage formulas but no chance. Current CoA uses ID 494043 for Rogue/Warden Blood Hound, a different conditional hit. [CoA Rogue/Warden list](https://chroniclesofarcadia.com/en/wiki/skills/list/3-7)
- [ ] Add pet defense stats before implementing Tough Oak's defense rider. Current CoA specifies +60% pet Physical Defense for the same Warden/Mage passive, while the RuneWaker component describes +5% physical-defense-percent; no pet Physical Defense baseline or mitigation formula exists in the simulator. Keep the rider unresolved rather than substituting armor or a WoW pet-defense formula. Current CoA pet skill IDs also differ from the local cooldown IDs; see [the source and runtime plan](ROM_WARDEN_MAGE_TOUGH_OAK.md).
### Mage
- [x] Apply current CoA's 30% base proc chance to Eruption 490221. The current [CoA Mage page](https://chroniclesofarcadia.com/wiki/skills/list/4?locale=en) identifies the passive and Fireball/Flame triggers; patch [10.2.1](https://chroniclesofarcadia.com/patch/10-2-1-1000) raises the base chance from 10% to 30%. No later base-chance change was found. Patch 12.1.0.5000 implies Elemental Catalysis also increases the chance but gives no value, and 10.2.1.1250 raises damage to “200%” without defining the baseline. The base chance is updated and tested; the EC bonus and damage interpretation remain unresolved. Existing damage formula is unchanged and is not source-verified.
- [x] Align Fire Ward (490248) with the current [CoA Mage page](https://chroniclesofarcadia.com/wiki/skills/list/4?locale=en): apply −11.5% received damage to every modeled magical school for the caster and party within radius 100 (10 runtime units); preserve local 120 MP, range 150 (15 runtime units), instant cast, and 10-minute duration because CoA omits duration. The hash-matched RuneWaker component 500366 grants +10 Fire resistance, which remains the runtime value; CoA lists +230 only at skill level 105, but there is no source-backed scaling curve or skill-level state to derive other ranks. The isolated catalog/aura regression passed (1 test), checking all six magical schools and excluding physical mitigation. Player and generated-companion party-scope/radius integration tests pass (2/2): each applies Fire Ward to the caster and eligible nearby party members, while excluding the distant party member.
- [x] Rank 2 Elemental Catalysis (497971) has no Mana tick: its RuneWaker tooltip omits Mana regeneration and component 620176 has `dotTime=0` and `dotBase=0`; rank 1's Mana tick stays rank-specific.
- [x] Current CoA Mage/Druid Green Guardian (494331) replaces the conflicting local passive/Protection-expiry HoTs for that exact pair. Players and generated companions gain one stack per full observed stationary second, up to 20, for +1% movement speed per stack. Companions auto-cast the learned zero-cost self skill on their first available combat action when the aura is absent; that is a simulator policy. A full stationary second after a sampled move is an explicit timing approximation. Stack loss and the MP refund remain unwired because the current CoA page gives no loss trigger or percentage basis. See [the source/runtime note](ROM_DRUID_MAGE_GREEN_GUARDIAN.md).
- [ ] Keep the local Mage/Warden Flame Follower (494051) passive unresolved: its critical-rate amount and Fireball trigger phase are unspecified, while current CoA has reworked Flame Follower under 490244 and reused 494051 for Purgatory Fire. Do not map the current active summon onto the old local passive by ID or name alone; see [the identity review](ROM_MAGE_WARDEN_FLAME_FOLLOWER_SOURCE_REVIEW.md) and [the raw source/runtime audit](ROM_MAGE_FLAME_FOLLOWER_RUNTIME_AUDIT.md).
### Druid
- [x] Druid/Warrior Cross of Thorns Attacks (499956) is emitted as a separate active elite skill from its local level-60 learn row (key item 546833, prerequisite 499955). It selects the source-backed two-hit Nature Power branch, and Briar Technique listens to 499956; 494018 remains a separate ability.
- [x] Record current CoA Spirit Guidance (local Charm 493536) rules in an isolated helper with 7 focused tests: players cannot be targeted; NPCs become friendly at nonnegative caster reputation and remain hostile below zero. CoA lists 16.2 seconds at +55 skill but gives no rank-duration formula, so do not reuse RuneWaker's local 3-second component as a universal CoA duration. Runtime faction/reputation state is still missing.
- [x] Record current CoA Rebirth rules in the same helper: Rebirth 493537 reduces death debt by 30% and optionally accepts an Amulet of Light or Golden Amulet for an unspecified extra reduction; Advanced Rebirth 493559 reduces it by 45% with required Amulet of Light (203606); Supreme Rebirth 493560 reduces it by 75% with required Golden Amulet (203605). Runtime death-debt units, rounding, inventory, and item consumption are not modeled, so this is source documentation/helper coverage rather than a claim of runtime implementation.
- [x] Current CoA Druid/Rogue Necrotic Wound (494321) and Corrosive Poison (494024) replace the conflicting RuneWaker effects for that exact pair: 25 Energy/12-second DoT poison; Wound requires poison plus one Nature's Power, spends 4% Mana once at channel start, hits three times for 329.7% Dark damage across 1.5 seconds, and spreads a fresh poison to targets within radius 8, with no Wound cooldown or old healing-reduction/root riders. The 150/80 CoA range/radius values map to 15/8 project units. The three 500ms hit timestamps and full poison refresh are documented simulator choices; CoA does not specify pulse timestamps or whether spread copies remaining duration. Player and companion spread regressions pass. The separate global 50% AoE multiplier remains unsupported. See [the feature note](ROM_DRUID_ROGUE_NECROTIC_WOUND.md).
- [x] Current CoA Sinister Request (494023) instantly refills each supported existing party resource pool to its maximum within radius 150 (15 project units), with the 15-second cooldown from patch 12.1.6.2004 and one-second successful-cast reductions from Poisonous Widow Embrace/Necrotic Wound. Player and companion paths respect positions/line of sight, living recipients, caps, and absent pools; companion AI selects it for a depleted nearby ally even when its caster is full. Focused catalog/runtime/AI validation passed 29 tests across four files. Source: [current Druid/Rogue skill page](https://chroniclesofarcadia.com/wiki/skills/list/8-3?locale=en) and [patch history](https://chroniclesofarcadia.com/patch/12-1-6-2000).
- [x] Current CoA Druid/Mage Inspiration (494322): a learned exact-pair passive now grants one stack per positive Nature's Power spend event (independent of points spent), capped at ten stacks for ten seconds. Current CoA says +2% Physical Attack Speed and Casting Speed per stack; runtime applies these through the shared melee/ranged/spell-haste consumers to the player and generated companions, including their modeled attack intervals, cast durations, and GCDs. The CoA page's Range 50 maps by the established 10:1 conversion to an interpreted five-unit caster-centered party radius; the living caster and party allies within inclusive 3D distance are recipients. One shared aura refreshes all stacks on each new spend because CoA does not specify per-stack expiry. Helper, catalog, and player/companion integration tests cover trigger, cap/refresh, radius filtering, and subsequent cast haste. Fireball's qualitative travel-speed rider and Nature's Power gain remain unwired: current CoA ID 499943 is likely local Fireball 490204's counterpart, but no source formally maps the IDs, gives a travel formula, or disambiguates the separate one-point grant timing. See [the source/runtime note](ROM_DRUID_MAGE_INSPIRATION.md).
- [ ] Keep the remaining RuneWaker Druid source and runtime gaps separate from current-CoA reworks. Revival Slash 499496 has a source-backed 25% child roll after original-target survival, but its hidden HolyHeal/HoT amounts still need per-spell rank, timing, flags, and native resolver integration. Learned Spring Flower child 499935 has a bound 30% +1 Nature Power effect and a 1/3/5% maximum-HP expiry-heal chain; its periodic healing formula is still blocked. Learned Inspiration Display child 499942 has ordered 60%-gated/30%-fallback checks and a timeout modifier, but no automatic cast from public Inspiration or Spiritual Gush is established. Quick Light Protection 494924's probability/heal/tie-break, Boiling Rock 494565's probability/MP amount, local Avalanche 494029's proc payload, and Extended Recovery 494200's Nature Power chance remain unresolved. Selectable native stats now provide source-derived effective MND/Wisdom, MDMG, Magic Power/MPow, HealPowerRate, HealPoint, and target-heal modifier channels. FIX row 303001 supplies Dmg_HealArg = 0.5. This closes the base stat/input-contract gap only: per-spell OrgPower, rank/skill evaluation, timing, flags, aura channel coverage, and the complete native healing consumer remain open. Current CoA does not fill these RuneWaker gaps. See [the source follow-up](ROM_DRUID_SOURCE_FOLLOWUP_2026-10-02.md).
- [ ] Implement the current CoA Spirit Guidance faction conversion and Rebirth debt reduction only after combat state can represent caster reputation/NPC faction and death-debt/item-consumption. The seven-rule helper is source documentation, not runtime support; the optional base Rebirth amulet bonus remains unquantified. Current CoA Druid/Rogue Necrotic Wound replaces the stale RuneWaker healing-reduction payload; see [the CoA behavior note](ROM_DRUID_ROGUE_NECROTIC_WOUND.md).
### Warlock
- [ ] Integrate current CoA Psychic Warrior (Warlock/Warrior 499868): area-damage spells summon a 187.5% main-hand DPS Ethereal Hammer; single-target damage spells summon a 1,050% main-hand DPS Ethereal Sword, both dealing Physical Dark damage. Patch [12.1.4.1500](https://chroniclesofarcadia.com/patch/12-1-4-1500) raised the area coefficient to 250%, then [12.1.5.1000](https://chroniclesofarcadia.com/patch/12-1-5-1000) reduced it to the current 187.5%; the [current pair page](https://chroniclesofarcadia.com/en/wiki/skills/list/9-1) confirms the current values. The catalog now uses the current name/tooltip and an isolated helper resolves the coefficients, but combat integration remains open until CoA's Physical Dark defense behavior and the added-hit event/roll semantics are sourced or explicitly decided; see the [source/runtime note](ROM_WARLOCK_WARRIOR_PSYCHIC_WARRIOR.md). The attribute-gated extra main-hand weapon damage for Slash/Consistent Heart Strike has no stated amount and remains open. Local 499869 is a separate learned level-70 Warlock/Warrior Mind Transference row (key 546844, prerequisite 499868, slot 25), not current-CoA Psychic Warrior or Enraged 499871. Its Rage-to-Soul-Point conversion is RuneWaker-only; see [the local source follow-up](ROM_WARLOCK_SOURCE_FOLLOWUP_2026-10-02.md).
- [ ] Update Breathing Control (Warlock/Warrior 498634) to the current CoA behavior: casts of Psychic Arrows, Warp Charge, Weakening Weave Curse, Slash, Soul Trauma, Puzzlement, Heart Collection Strike, or Surge of Malice can trigger Enraged automatically, replacing RuneWaker's cooldown-reset behavior. The [10.7.1 patch](https://chroniclesofarcadia.com/en/patch/10-7-1-2000) documents the behavior change, and [11.1.2](https://chroniclesofarcadia.com/patch/11-1-2-1000) documents the expanded trigger list. The proc probability and precise event timing are not published; leave the current-CoA proc unwired. The local RuneWaker collections/scripts have no bound trigger contract for 498634/499870. See [the local source follow-up](ROM_WARLOCK_SOURCE_FOLLOWUP_2026-10-02.md).
- [ ] Keep Deep Breathing Control (Warlock/Warrior 499870)'s 15% HP rider unwired until its trigger is explicit. The current CoA row says “Your Breathing Control recovers more focus and an extra 15.0% HP,” and [11.1.2.3000](https://chroniclesofarcadia.com/patch/11-1-2-3000) raises the rider from 10% to 15%, but neither source says whether HP recovery occurs on manually cast Enraged 499871 or only when Breathing Control 498634 automatically triggers Enraged. The current CoA Breathing Control row leaves proc probability/timing unspecified, and local 498634/499870 rows have no bound checks, components, or callbacks. Do not attach the heal to manual 499871 without a source-defined event link; the extra Focus amount also remains unknown.
- [x] Replace Warlock/Rogue Soul Raid 498678 with current CoA Shadow Slice when the passive is learned. Patch [10.4.0.4001](https://chroniclesofarcadia.com/patch/10-4-0-4000) reworks Soul Raid to modify Shadow Step 490344 into a 1-second stun, 4,400 Dark hit, +30% Dark damage, and +10% movement speed for 30 seconds; [10.4.1](https://chroniclesofarcadia.com/en/patch/10-4-1-1000) sets Psi recovery to 3. The catalog/tooltip and player/companion cast mechanics are integrated. The simulator cannot model the shadow's behind-target positioning, and CoA gives no lower-rank damage curve, so 4,400 remains a flat amount. The local +10%/+10% six-second component is not layered onto the learned CoA rework.
- [ ] Keep current-CoA End of Thought unwired until its version-specific periodic contract is sourced. The local RuneWaker 498699 is a separate Warlock/Rogue skill: its pre-hit <=35%-HP callback applies a four-second buff, whose one-second child lacks a located native timed-magic consumer. The local callback is source-backed, but its periodic Soul Point effect is not executable from the inspected server tree. See [the local source follow-up](ROM_WARLOCK_SOURCE_FOLLOWUP_2026-10-02.md).
### Champion
- [x] Verify Shield Form (498562) learnability: the local Champion-primary level-16 learn row exists behind Dwarf Champion flag 546211 and a quest grant. The exporter omits its flag-keyed row, so absence from the generated player catalog is not absence from source. Its toggle/child payloads and skill-rank acquisition semantics remain unimplemented; see [the source audit](ROM_CHAMPION_REMAINING_MECHANICS_AUDIT.md).
- [x] Integrate source-backed Rank-2 Forge/Chain Drive: its normal-attack event keeps Forge stack and Rage results even when the later effect roll fails; the 80% Shield Form-buff check precedes a separate 30% fallback, with the target resolved once. The eight-second effect resets Rune Pulse through EndUseLua. Rune Pulse grants +20% outgoing physical/magical damage for one second at cast acceptance, expiring before its two-second impact.
- [x] Add the missing rank-1 Forge companion auto-attack event path with owner/expiry-qualified eligibility. A fully absorbed swing does not proc; a landed normal swing applies its own stack and +10 Rage before the ordinary +6. Focused Forge, Champion, and party-runtime coverage passed 74 tests across three files. The final post-fix 8 GB TypeScript/Vite build, asset audits, bundle verification, exact-final-dist Cat QA, and `npm run release:check` passed; release check covered 94 changed paths, including untracked files.
- [x] Integrate Dark Energy Strike 498599's ordered physical then Shadow packets and 15% cast-level Rune Siphon reset. The reset rolls once only after the physical packet produces a surviving positive result; the later Shadow result does not gate it. See [the source/runtime follow-up](ROM_CHAMPION_SOURCE_FOLLOWUP_2026-10-02.md).
- [ ] Keep the next-Curse instant-cast rider and full Shield Form/Rune Overload target behavior open until their transform, child-state, and target-processing contracts are complete.
- [x] Confirm Rune Overload's RuneWaker identity before comparing it with current CoA: the local generated catalog maps 498572 to Rune Overload and 498571 to Remodeled Body, while the [current CoA Champion/Rogue list](https://chroniclesofarcadia.com/en/wiki/skills/list/10-3) maps 498571 to Rune Overload and 498572 to Runecraft - Haste. The current page and patch history describe a later skill revision; preserve the local RuneWaker names, costs, and values rather than crossing the ID collision.
- [ ] Wire local Rune Overload (498572)'s one-second on-time child tick into player and companion runtime. Catalog work now resolves hidden MagicCollect 498574 from component 621243 as a 0.6 physical-damage coefficient and removes the unsupported 10-yard radius heuristic; the isolated catalog/resolver tests pass (16 tests across the hidden-child and Champion runtime files). RuneWaker component 621241 supplies the one-second `onTimeMagicId` link, but runtime has no autonomous consumer for it; the periodic proc path only receives existing DoT/HoT ticks. The local tooltip says the child hits nearby targets, but the source has no numeric radius or target cap, so target selection remains unresolved and must not be guessed.
## 2026-10-03 — Native RoM five combat and rotations
- [x] Route source-bound native HolyHeal and supported positive magical DotMagic healing through player and companion consumers, including effective Holy Blessing Wisdom and recipient absorption once. Actual player/NPC Heal, Urgent Heal, and Regenerate regressions pass.
- [x] Use verified source attack and automatic training-weapon channels for the five active native builds, with explicit unsupported-component/custom-gear fallback. The resolution follow-up adds native source defense, hit/avoidance and critical consumers for exact imported NPCs; unsupported source inputs retain the shared fallback.
- [x] Add exact-pair native rotations, emergency/group triage, actor/target-owned periodic refresh, and conditional setup/AoE decisions. Public KittyCombo/CoA research informs clean-room policies; the add-on archive was blocked by a Cloudflare challenge, so no imported presets are claimed.
- [x] Run the requested fixed full-player/four-NPC cohort at levels 1/10/30/60/65/66/79/80 against Barren Caves trash and Anglo. All 80 pulls finish without player/NPC deaths or invalid casts. Native-only health budgets give 4.5–9-second trash and 39–53.4-second Anglo pulls in this static diagnostic. Scene mechanics and movement are outside the diagnostic.
- [x] Restrict ordinary RoM companion generation to Knight, Priest, Rogue, Scout, and Mage; explicit configured builds remain constructible for targeted work.
- [x] Add source-negative HP/HP_Per DotMagic application snapshots and ticks for native player, native companion and imported enemy consumers. Source tick defense/resistance is snapshotted once; current MaxHP is read for HP_Per ticks.
- [x] Add native source target-defense/hit/critical consumers, exact per-actor mode dispatch, active-five Throw/ShieldDef inputs and real target-count/ordinal falloff. Keep unsupported source/gear branches explicit.
- [x] Retain enemy damage calculation, attack kind and elemental school independently for WoW and RoM, with source-ID namespaces, DBC school masks and authored fallbacks for missing/non-damaging source rows.
- [x] Resolve supported native NPC equipment and exact fixed/recipient-MaxHP enemy packets; test Anglo movement, interruption, control targeting and player/NPC dispels. Measure enemy damage separately from ability health costs and calibrate the native shared-damage budget through level 80. Source/manual packets bypass that budget. The recovery/equipment follow-up implements source ReHP/ReMP and resolves all 440 imported NPC defaults; unsupported formula shapes and broader sustain certification remain open. See [the enemy/encounter pass](ROM_NATIVE_ENEMY_ENCOUNTER_PASS_2026-10-03.md), [recovery source audit](ROM_NATIVE_RECOVERY_SOURCE_2026-10-03.md), and [equipment completion](ROM_NATIVE_NPC_EQUIPMENT_COMPLETION_2026-10-03.md).
- [x] Implement native source ReHP/ReMP for player/owned NPC actors, resolve all 440 imported NPC equipment defaults, preserve compatibility boss mechanic windows, and correct early native weapon-start/Mana-spending decisions and training budgets. The final fixed 80-pull cohort passes without deaths/invalid casts; see [the recovery/equipment/pacing follow-up](ROM_NATIVE_RECOVERY_EQUIPMENT_PACING_PASS_2026-10-03.md).
- [ ] Complete remaining unsupported source shapes and broader native combat parity before any readiness promotion. RoM builds remain Needs Testing. Level cap stays 80; no loot wiring or readiness promotion.
See [the original implementation report](ROM_NATIVE_COMBAT_PASS_2026-10-03.md) and [the native resolution and damage-type follow-up](ROM_NATIVE_COMBAT_RESOLUTION_PASS_2026-10-03.md). The earlier pacing numbers above describe the historical amount-only diagnostic; the follow-up records the final native-resolution run.
+96
View File
@@ -0,0 +1,96 @@
# Bite-Sized spot authoring
Open **GM Menu → Bite-Sized Editor**, select a dungeon and spot, and use **Go to spot**.
GM administration also provides the same entry. A selected character and an online
GM account are required. Leave an online activity or Dungeon Race before editing.
The scene uses the normal renderer, movement, and hold-right-drag camera. The right
panel scrolls and collapses to leave the world visible. Click the world or press
**Walk in scene**, then use **WASD** to move, **Space** to jump, and hold the
**right mouse button** to look. Focusing a panel control suspends movement and
camera input until you return focus to the scene. The panel can stay open while
you walk and place points.
- Select Party start, Random boss spawn, or an individual mob point. Walk to a
grounded position and press **Set here**, edit coordinates/facing, or use
**Go to point**. Cyan markers show all five party seats, yellow markers show
mobs, and the red marker shows the random boss anchor.
- The searchable mob picker starts with the full parent dungeon. **Other dungeons**
includes imported mobs and their source names. Each point is independent;
repeated creature types are supported. Assets are prepared before previews.
- New spots start empty with **After all mobs die**. A zero-mob layout activates
its boss immediately. **Present from start** activates it alongside the mobs.
Ordinary bosses always come from the parent dungeon and are rolled per run.
- New spots use the parent's full geometry without the original artificial
branch closures. Duplicates retain the copied spot's legacy closures.
- **Test run** exercises the draft with combat, completion, and no saved rewards,
progression, checkpoints, or rankings. **Return to editing** starts another
placement session. A test completion appears in the panel.
- **Save & publish** validates the draft's references, IDs, transforms, grounded
anchors and reachable navigation. Keep at least one spot in every dungeon.
Imported layouts also validate their retained permanent branch closures.
A revision conflict or download/validation failure leaves the draft intact.
**Refresh published** preserves a dirty draft; **Discard** restores published
data. Drafts are held in this client session until published or discarded.
## Runtime and persistence
`shared/bite-sized-layouts.mjs` owns normalization, gameplay identity, and independent
deterministic location, spot, mob and boss rolls. Ordinary runs choose a spot
uniformly within their dungeon and retain its creature types. Randomized activities
keep the two existing source pools, choose an eligible parent dungeon and spot,
then deal rolled creatures into those placements without replacement until a pool
is exhausted. Both activity IDs remain unchanged for saves and network protocols.
`BiteSizedRunSelection` includes the complete immutable layout snapshot, its stable
ID/gameplay revision, parent source, boss and resolved mob references. Checkpoints,
online activities and race matches pin it. Publishing affects new runs; retries,
offline cached resumes, party members and race opponents retain their snapshot.
Legacy checkpoints keep the original layout, and legacy randomized runs preserve
the original Stockades creature deal.
`src/game/biteSizedLayoutRuntime.ts` materializes placements over the selected parent
definition. `contentSourceDungeonId` controls environment, navigation and artwork
resolution. `src/app/biteSizedLayoutContent.ts` verifies that parent's content and
selected creature assets before entry and retains a bounded preparation cache.
Published configuration is cached in local storage; checkpoint snapshots do not
depend on the latest configuration being available online.
`server/bite-sized-layouts.mjs` owns SQLite `bite_sized_layout_config` and immutable
`bite_sized_spot_revisions`. Public reads use `/api/bite-sized-layouts`; authenticated
GM reads/writes use `/api/gm/bite-sized-layouts`. PUT accepts `{ expectedRevision,
config }`. `?spotId=<id>&revision=<number>` reads archived data, including removed
spots; `?history=1` lists historical revisions. Gameplay edits create timing
revisions, while renames retain the timing revision and immutable historical data.
Dungeon and race clear-time rankings include spot ID/revision alongside existing
boss/difficulty dimensions. Existing results migrate to the original default spot,
revision zero. Results carry spot names; timing screens expose spot and revision
filters. Overall race wins keep their aggregate dimensions.
## Generated owners and verification
Run `npm run bitesized:generate` after changing parent definitions, supported source
creatures, or navigation assets. `scripts/generate-bite-sized-layouts.ts` emits
`shared/bite-sized-defaults.json` and `shared/bite-sized-catalog.json` from the
authoritative registry/templates. `scripts/generate-bite-sized-navigation.ts`
emits a compressed API-side navigation surface/reachability index and bundles the
same TypeScript floor validator into `server/generated/`. These artifacts must ship
with the API server; the server does not need rendering downloads for validation.
Focused coverage lives in `src/game/biteSizedLayouts.test.ts`,
`src/game/biteSizedLayoutsStore.test.ts`, `src/app/biteSizedLayoutContent.test.ts`
and `server/bite-sized-layouts.test.mjs`, alongside the existing dungeon, content,
checkpoint, online, race and input tests. Run `npm run build` and
`npm run release:check` before delivery.
`node scripts/playtest-bite-sized-editor.cjs` runs Edge against an isolated temporary
API database and the dev app at port 5173. Override `BITE_SIZED_EDITOR_URL` when
using another dev port. It records WoW/RoM authoring, imported previews, both boss
settings, completion and unranked safeguards, panel input gating, right-drag release
without pointer lock, and randomized entry into distinct parent maps under
`playtest-artifacts/bite-sized-editor/`.
Set `BITE_SIZED_EDITOR_INPUT_ONLY=1` for a focused WASD, panel-focus, combat-gating
and right-drag check. It writes `editor-movement.png` and
`movement-observations.json` in the same evidence directory.
+77
View File
@@ -0,0 +1,77 @@
# Character equipment appearance
The shared `src/avatar/CharacterModel.tsx` renders the player, party NPCs,
roster, and creator. Equipment appearance is presentation-only; it never
changes item ownership, stats, or progression.
## WoW and Ascension
`src/avatar/equipmentAppearance.ts` keeps exact appearances for the packaged
Wailing Caverns drops. Unmapped armor, including synthetic heirlooms, gets a
representative native WoW appearance by equipment slot and armor type. Empty
preview slots receive starter clothing: chest, legs, boots, gloves, shoulders,
and cloak. Cloth uses a robe, leather uses leather armor, and heavy armor uses
the packaged mail breastplate. These are visual defaults, not exact item skins
for every entry in the loot catalog.
Real equipped appearances override the starter appearance in their slot.
The body atlas layers remain ordered so robes override the trouser geoset.
Appearance cache keys include class, item slot, and armor type.
`src/ui/CharacterPreview3D.tsx` passes the saved player's equipped inventory
items into the same renderer used in the dungeon.
Loaded preview attachments request a bounds refit when their optional models
finish loading, so larger native staffs stay inside the roster preview.
## RoM
The native shared-skeleton character GLBs contain original RoM starter
garments. `scripts/runewaker-pipeline/recipes/player-starter-appearance.tsv`
selects `cloth010-001` for torso, hands, legs, and feet instead of the bare
`body000-001` defaults. This common starter outfit is currently shared across
classes; individual RoM armor drops do not yet replace those modular parts.
Rebuild all five supported race/gender rigs with
`npm run runewaker:players:avatars`.
`src/avatar/runewakerEquipment.ts` resolves original RoM starter sword, mace,
shield, staff, bow, and dagger props from
`public/assets/equipment/runewaker-v1/`. Equipped weapon types select the
appropriate representative source prop. Exact skins for arbitrary equipped
RoM weapons are not implemented. WoW texture atlases and WoW item models must
not be applied to the native RoM rigs.
Rebuild the props with:
```text
node scripts/runewaker-pipeline/build-population.mjs --recipe scripts/runewaker-pipeline/recipes/runewaker-starter-weapons.json --actors-only
```
The generated import manifest records the source ROS path, source SHA-256,
output SHA-256, bounds, and triangle count for each prop. Converted source
props retain the RoM socket frame; the WoW-to-RoM procedural fallback rotation
must not be applied to them on native rigs. The bow retains its native facing
on RoM rigs. On the basic human fallback, its source Y axis is aligned to the
bow socket before applying the inverse socket adaptation, keeping the string
toward the archer. Other props retain their source orientation.
Weapon selection follows RoM class identity even when the optional character
pack is absent. The basic human body retains its WoW clothing and shoulders,
but its hands receive original RoM props with the inverse socket adaptation.
The optional character pack is not required to see authentic RoM weapons.
## Packaging and validation
All equipment files belong to the bundled `core:equipment` content pack.
RoM character rigs belong to the optional `characters:runewaker-v1` pack.
Refresh local content with `npm run content:publish` after regenerating assets.
Existing installations must refresh their content packs to receive changed rigs.
Each optional item retains its own Suspense/error boundary and procedural hand
fallback. Missing item assets cannot hide the body or other equipment.
- `npm test -- --run src/avatar`
- `npm run build`
- `node scripts/playtest-party-equipment.cjs` after building and refreshing content
- `node scripts/playtest-party-equipment.cjs --rom-only --basic-only` checks the missing-character-pack path
- Review roster and dungeon screenshots in `playtest-artifacts/party-equipment/`
- Record visual findings in `PLAYTEST_NOTES.md`
- `npm run release:check`
@@ -0,0 +1,60 @@
# Character stat rulesets
Character origin and character stat rules are independent. RoM characters can select Native RoM or WoW compatibility from the main menu. WoW characters retain WoW rules.
## Saved profiles
- Existing saved profiles without a valid `statRuleset` normalize to `"wow"`. This preserves the pre-existing RoM compatibility calculations, including their hybrid base-stat behavior.
- Newly created RoM profiles explicitly select `"rom"`; newly created WoW profiles select `"wow"`.
- The selector updates only the selected character. Inventory, equipment, progression, class pairing, learned skills, bindings, loadouts, and dungeon checkpoints remain attached to that profile.
- Switching is restricted to the main menu and blocked while a character remains active, a live enemy is engaged, or an online group activity is live. The combat check uses the installed dungeon runtime bridge so the main menu does not eagerly import combat catalogs. A failed storage write reports failure and retains the saved choice. A failed migration write still leaves the existing roster readable and retries on a subsequent read.
- Cloud saves retain the profile field because the client and server persist complete profile objects.
`src/game/characterStatRuleset.ts` owns normalization. `src/app/accountRepository.ts` owns profile migration and persistence; `src/app/shellStore.ts` owns the switch action; `src/ui/MainMenuScreen.tsx` owns the selector and controller actions.
## Native calculation and shared combat
Native inputs must retain their source meaning. Wisdom is RoM MND. Physical and magical attack, defense, damage, and combat points are distinct source channels. Native hit/critical/dodge points must never enter WoW rating-to-percent conversions.
Native derived calculations are sourced from the local RuneWaker `RoleAttr.cpp` and player vocation/race/sex/fixed-argument database records. Secondary-class activation at level 10 and treating the secondary level as the main level remain simulator policies.
`src/game/romNativeStats.ts` owns derivation and source-unit modifier re-derivation. `romNativeStatsTypes.ts` keeps native points and multiplicative rates separate. `scripts/runewaker-pipeline/export-rom-native-stat-rules.mjs` owns `src/game/generated/romNativeStatRules.generated.json` and the compact `romNativeGearCurves.generated.json`; runtime code does not import the full reference item catalog. The existing `romStats.ts`/base-growth path remains available for legacy compatibility.
Equipped native items carry `ItemStats.romNative`. Their common WoW projection is not counted again. Foreign items without that payload bridge only direct Strength, Stamina, Intellect, Agility, and flat health/mana under an explicit simulator policy. Spirit does not become Wisdom; WoW armor, attack/spell power, weapons, and ratings do not become native channels. The five existing source-reference heirloom classes supply native gear curves; other classes retain the direct-stat fallback until native gear profiles are sourced. Reference item selection and intermediate-level interpolation remain synthetic simulator policies.
The RoM automatic fallback is displayed as Training gear, not an authentic heirloom system. Player and NPC training gear scales through level 79; character base growth continues through level 80. See `docs/ROM_FIVE_NATIVE_SCALING_2026-10-03.md` for the five-class follow-up, owner parity, enemy health policy, and validation. This does not introduce loot progression.
The follow-up's exact-dist check supersedes the browser artifacts at the shared `playtest-artifacts/stat-rulesets` path. Its final chunks and eleven screenshots are recorded in that follow-up; the validation totals below describe the original stat-ruleset implementation.
The dungeon combat system selects native source resolution for supported canonical RoM builds against exact imported RuneWaker NPCs, in either direction. Unsupported source inputs and WoW-mode actors retain the shared compatibility resolver. Adapting a native stat into a common field alone is not evidence of native formula parity. The latest [native resolution follow-up](ROM_NATIVE_COMBAT_RESOLUTION_PASS_2026-10-03.md) records supported channels and remaining source boundaries.
The common fallback adapter uses native ATK as attack/ranged attack power, MDMG as spell power and DEF as armor, with shared WoW mitigation only on that fallback. The supported native resolver directly consumes source ATK/DEF or MATK/MDEF and native hit/critical/dodge/parry/block points without converting them into common percentages. Existing primary resources and regeneration policy remain part of the shared simulation; native MP also supplies supported secondary mana pools. The Equipment panel labels native points explicitly and shows active native aura effects for its selected owner. DEF displays its source value without presenting a WoW armor percentage as native mitigation. Shared HUD counters display whole HP/MP values while runtime pools retain precision.
Player FIX record 303001 sets `DmgAtkArg` and `MDmgMAtkArg` to zero, so this source version derives DMG/MDMG from flat gear channels rather than ATK/MATK. Its `Dmg_HealArg` is **0.5**. Wisdom/MND, MDMG, MPow, HealPowerRate, HealPoint, and target heal-modifier inputs now have explicit source channels. Per-spell OrgPower, rank/skill-level evaluation, timing, flags, and the complete native healing consumer remain separate work. These local RuneWaker records do not certify current-CoA formulas or balance.
The character, party member, and combat actor retain their own ruleset. No global party or dungeon setting chooses every participant's stat system. This provides a foundation for future mixed parties; matchmaking and cross-game balance certification are outside this change.
## Compatibility evidence
`src/game/generated/characterStatRulesetCompatibility.json` freezes 18 pre-change stat outputs across WoW characters and legacy RoM builds, including gear, modifiers, race, level, and secondary-class cases. `src/game/characterStatRulesetCompatibility.test.ts` checks both omitted rulesets and explicit WoW compatibility against those outputs. This fixture is a simulator regression baseline, not native RoM source data.
## Validation
- 219 focused tests passed across 22 files, with four existing IndexedDB skips: the final 21-file selection passed 211 tests, and the independent native runtime suite passed eight. The source/gear worker's 30-test selection overlaps these totals.
- The runtime suite covers per-owner mode, primary and secondary Mana mirrors, level-10 secondary activation, Wisdom/Holy Blessing and GM-buff cap removal, periodic/channel source amounts, native party autoattacks, and exclusion of foreign WoW attack/critical/hit/haste ratings.
- Ready-five passed seven Vitest and twenty Python checks. Avatar validation passed 47 tests across ten files.
- The final full 8 GB TypeScript/Vite production build passed, including prebuild asset audits, compression, and release-bundle verification. A subsequent TypeScript project check also passed after the final test edits.
- Exact-final-dist Edge QA passed through `scripts/playtest-stat-rulesets.cjs`, using an isolated temporary offline account. New-profile defaults, synthetic legacy migration, independent saved choices, build/checkpoint preservation, both dungeon modes, switching locks, native panel tabs, and desktop/390-pixel layouts passed. Roster and both dungeon screenshots show character bodies and held starter staffs. There were no page errors or application-resource response errors; the optional favicon returned 404.
- Browser evidence: `playtest-artifacts/stat-rulesets/results.json` and its ten referenced screenshots. The checked chunks were `index-CGkT8hBz.js`, `combatStore-CVXgxk1Z.js`, and `PartyFrames-BeW5_TCA.js`. Synthetic engaged-mob and online-activity fixtures verify the menu guards, not a real multiplayer session.
- Final `npm run release:check` passed for 157 changed paths, including untracked files and concurrent unrelated work. Final documentation and owned vault notes satisfy text-file hygiene.
- No full repository suite, all-class balance sweep, RoM readiness promotion, matchmaking, or deployment was performed.
## Native combat amount follow-up (2026-10-03)
This section records the original amount-only pass. Its open native hit/defense/periodic and target-context boundaries are superseded by [the native resolution and damage-type follow-up](ROM_NATIVE_COMBAT_RESOLUTION_PASS_2026-10-03.md), which also records the newest pacing and browser evidence.
`romAbilityCatalog.ts` now carries explicit `romNativeSource` skill/component identities into bound effect amounts. `romNativeCombatAmount.ts` dispatches supported native direct damage, direct HolyHeal, and periodic HolyHeal snapshots from `equipmentAdjustedCombatAmount`; an unsupported source binding or required gear profile leaves the existing shared HealerMan amount fallback in place. Native `MagicProc.MagicLv` currently uses character level clamped to 1–80 as a simulator rule. Active five-build companion casts use the player-build source branch even when the owner is a party NPC.
Direct HolyHeal now uses the source OrgPower/MND/MDMG/MPow/HealPowerRate/HealPoint path with mean variance. Recipient HealAbsorbRate and flat HealAbsorb are applied once at the actual target, then existing generic combat-result stages resolve criticals and overheal. Periodic HolyHeal uses its separate source DotMagic rank correction and snapshots the integer tick amount when applied; player and NPC targets reuse that fixed tick snapshot. Source auto profiles cover player Knight main-hand attacks and NPC Knight/Rogue melee plus Scout Bow attacks, with NPC Rogue offhand. Player Rogue offhand handling requires an explicitly present equipped inventory item. Player Scout Shot uses the native direct-damage route for its actual bound Shoot hit, not a continuous native bow-auto profile. Caster ambient basic attacks retain generic timing and MDMG policy. Player melee haste explicitly reads the existing common aura because native stat re-derivation does not populate common haste fields. Element-specific MPow/BodyRate, unsupported source components, native hit/avoidance point consumption, complete native defense/variance resolution, and full source combat parity remain open. The damage consumer declines share-damage and target-ordinal decrease branches until runtime supplies exact target-count context. Custom/unverified gear cannot enter the source direct-damage training-weapon route and keeps the shared fallback.
The five exact-pair rotation and final full-player diagnostic are tracked in [`ROM_NATIVE_COMBAT_PASS_2026-10-03.md`](ROM_NATIVE_COMBAT_PASS_2026-10-03.md). The post-haste-retention report covers 80 fixed pulls at levels 1/10/30/60/65/66/79/80: all cleared with zero player/NPC deaths and zero invalid casts; trash took 4.5–9 seconds and Anglo 39–53.4 seconds. The scoped health factor applies only to native-stat RoM and leaves legacy WoW-stat RoM, WoW/CoA-origin health, enemy damage, and the level-80 cap unchanged. Source-damage follow-up passed 13 cases: seven helper cases, two player/companion amount-parity and Reflected Shot fail-closed cases, and four actual auto/source-action cases for player Knight main hand, NPC Scout bow, NPC Rogue offhand, and player Scout Shot. Player Rogue offhand handling requires an explicitly equipped inventory item. Player Scout Shot uses the native direct-damage route for its bound Shoot hit. Caster ambient basics keep generic timing/MDMG policy. Final production build and TypeScript project check passed with asset audits, compression, and bundle verification. Exact-dist browser QA passed with 11 screenshots captured and four representative roster, dungeon, NPC-stat, and mobile screenshots visually reviewed. Current chunks were `index-D_h9IRuA.js` and `combatStore-BiA9BOQG.js`; there were no page/server errors and the network response-errors list was empty, with only the optional existing favicon 404 in the console. A release check passed on 249 paths; the final docs update requires the final hygiene/release check. The earlier 60-sample, six-level report is retained as a historical baseline. The ordinary randomized companion pool is now restricted to the active five identities while the configured factory is broader; no pool/readiness promotion is included. No loot wiring, level-cap increase, or legacy/global enemy-HP retune is included.
@@ -0,0 +1,11 @@
# Chronomancer resource baseline
Chronomancer now initializes the expected 414 mana at level 1. The committed baseline initialized 369; both the earlier working-tree run and saved HEAD-source replay reproduced that mismatch, establishing that it predated the recent RoM changes.
The intended bonus is sourced by Chronomancer's automatic `Chrono Sorcery` passive in `src/game/generated/coaAbilities/chronomancer.json`: its Aura 132 modifier increases maximum `power` by 0.12. Source MiscValue 0 identifies Mana. The human level-1 derived pool is 123 mana before the global 3x pool multiplier, so the expected result is `round(123 × 1.12) × 3 = 414`. The generated description still contains `$s1%`, which the old description-only path could not resolve. The runtime now consumes the structured modifier directly.
`src/game/classPassiveResourceModifiers.ts` converts structured permanent passive Aura maximum-resource percentage effects into source- and rank-preserving `TalentModifier` entries. Aura 132 uses its source power identity; generic power without that source channel uses the class profile. Explicit resources stay scoped, and matching parsed duplicates are removed. Other-recipient, timed and hit/crit-gated effects stay excluded. This preserves Sun Cleric's Rage and Necromancer's Runic Power as separate resources instead of expanding their Mana.
The root runtime integration is complete. Nine helper checks and the original selected combat-store resource case pass, including Chronomancer's 414 pool and the unchanged other class/resource expectations. The original case and expectation were preserved. No all-class balance run was used.
See `docs/STOCKADE_ENEMY_MECHANICS_2026-10-05.md` for the coordinated build and validation totals.
+99
View File
@@ -0,0 +1,99 @@
# CoA catalog promotion — October 3, 2026
The active catalogs now use the pinned August 12 Vol'Jin talent capture and global
BASE spell evidence. CoA remains **Needs Testing**. This completes the source and
catalog foundation for further class mechanic implementation.
## Source selection and offline reuse
The builder capture comes from `srhinos/coa-datamine` revision
`5078f9ac22541c45c17a866c23aac6c12073de23`. CoA spell/class evidence uses the paired
local client extraction's global `patch-T` Spell, `patch-M` class metadata, and
`patch-S` supporting tables. Classic Ascension data retains its original Area 52
records, including linked spell payloads. Separate accessors prevent shared IDs
from crossing those scopes.
The archive supplements your extraction rather than replacing it. Its supporting
tables match the local copies. Eleven missing August node spell IDs were found
in the archive's global patch-T table. The selective download cached 26 compressed
raw shards (4,650,843 bytes) and selected 48 records including class-only references
and linked payloads. Forty-one records supplement missing local global rows.
It retains all raw columns and inferred types, with pinned metadata and checksums.
No full client archive or repeated Exiles crawl is needed.
`npm run coa:reference:promote` reads verified local caches. Promotion and historical
reference rebuilds produced identical bytes with network access disabled. The
lossless July baseline remains tracked separately for comparison.
## Active catalog changes
- 21 classes, 91 playable tabs, and 3,618 nodes: six added, 436 changed, none removed.
- 701 ability entries and 2,917 talent entries, with 3,933 node-rank references.
- Resolved 174 encoded description fields from the original builder capture.
- Regenerated all 21 CoA runtime and talent UI shards. Non-CoA talent runtime
records and UI shards are unchanged.
- The runtime catalog has 1,276 ability families, 3,395 ranks, 3,348 distinct
rank spell IDs, and 578 hidden triggered payloads. Sourced starter spells
include class-catalog-only references such as Rejuvenating Venom.
- Exported six missing icons from local BLPs, with zero placeholder fallbacks.
- Preserved all 1,822 progression-chain identities, 1,266 classic chains, 7,268
protected classic spell records, and the outputs of all 612 classic abilities.
The six added nodes are Mycelial Healing, Devourer, Dark Channeler, Crusher,
Houndmaster's Whistle, and Skewer. Full before/after evidence and coverage gaps
are in `data/coa-reference/promotion-report.json`.
## Saved builds and remaining work
Saved CoA node keys remain resolvable under their original class. Saved ranks
clamp to the captured maximum. Source changes include Agonizing Burns 1→2, Timed
Attacks 2→1, Cultist node 6274 2→1, and Advisor's Perfidy 2→1.
Numeric IDs are not a guarantee of identical effects across source versions.
August swaps the spell payloads of Agonizing Burns/Timed Attacks. It also swaps
Dark Infusion/Darkward between Cultist nodes 30036 and 6274, including a change
of tree. Existing saves contain no CoA capture-version metadata, so this update
does not attempt an ambiguous semantic migration. Affected builds need review.
All August node ranks have global DBC evidence. Thirteen older progression ranks
are absent from both selected global sources: 501862–501865, 501918–501920,
501922–501925, 502889, and 560469. Their IDs are retained and gaps are reported.
The wider catalog/context audit reports 224 missing BASE spell records and three
source connection warnings. These are not filled from Area 52.
Descriptions and client effects do not establish server-side proc timing,
acquisition rules, or complete class behavior. Bespoke mechanics and targeted
player/companion tests remain the next class-by-class phase.
## Validation and browser evidence
All 44 pipeline/cache/source-policy tests and 62 focused game tests pass. The
focused tests verify source separation, classic preservation, saved-rank
clamping, runtime shard loading, sourced spell semantics, and explicit source
gaps. Ready-five checks pass (7 game tests and 20 Python checks); no all-class
balance sweep was run. All 21 runtime shards match their generated snapshot.
The negative DBC cast-time sentinel on Berserker Axe is retained in source
evidence and clamped to an instant CoA runtime cast. Classic behavior is
unchanged. A Tinker resource test was corrected to copy the matching maximum
pools alongside the current pools; no production stats behavior was changed.
With network requests blocked, fetch reuses the complete cache, promotion repeats
identically, and historical build/audit/lookup succeed. The promoted candidate
SHA-256 is `9208e973c43c31d263fb429f7ab82a2cc6732e2a70bc14f482b6428c9b296091`.
The historical snapshot is
`e86031775dfac7e336361087c50ca23a0a7a86c36a760c85803bee4bcdb89351`.
The production build and release-bundle verification pass. A browser smoke check
created the local offline `Coaaudit` Witch Hunter and opened its five talent tabs.
Houndmaster's Whistle displays the new icon, full description, and prerequisite
gate. No warning/error logs were captured. This checks presentation at level 1;
it does not exercise unlocked combat mechanics.
The optional local API server was absent during this offline preview. Development
proxy policy/layout requests failed and offline defaults were used. Online roster
and server policy synchronization were outside this check.
Screenshot: `playtest-artifacts/coa-catalog-promotion/houndmaster-whistle.jpg`.
See [the pipeline guide](COA_REFERENCE_PIPELINE.md) for repeatable commands.
+563
View File
@@ -0,0 +1,563 @@
# First Conquest of Azeroth party
Updated: 2026-10-05. The project owner selected these five classes as the first
CoA implementation milestone. Build and refine this party before expanding to
other CoA classes. CoA here means Conquest of Azeroth on Vol'Jin; the existing
RoM backlog's Chronicles of Arcadia references describe a different game.
| Seat | Class | Initial specialization | Responsibility |
| --- | --- | --- | --- |
| 1 | Guardian | Vanguard | Tank |
| 2 | Witch Doctor | Brewing | Healer |
| 3 | Barbarian | Brutality | Melee damage |
| 4 | Ranger | Archery | Ranged damage |
| 5 | Pyromancer | Incineration | Caster damage |
Begin with each class's core kit and the selected specialization so the full
party can enter targeted playtests early. Finish the remaining trees within
these five classes before expanding to the other classes. This selects work;
it does not certify the current implementations.
## Implementation order and acceptance
1. Freeze the five class/spec identities and reproducible diagnostic inputs.
Inventory every node, rank, source spell, and current runtime mapping. Author
reviewed talent allocations instead of treating generated role-weighted
allocations as an intended CoA build.
2. Establish the tank and healer loops together, including their resource and
persistent state. Check damage, mitigation, threat, healing recipients,
periodic effects, and party utility against the captured evidence.
3. Implement the three distinct damage loops and their talent interactions.
Share combat primitives where their semantics match, while keeping class
state and learned-rank ownership on the correct actor.
4. Test the same party against explicitly selected encounters. Repeat with
each class as the active player and the other four as companions. Include
single-target and multiple-target pulls, incoming party damage, interrupts,
dispels, cooldown use, resource exhaustion, death, and resurrection where
the selected kits provide them.
5. Fix observed mechanic and AI defects, then inspect live dungeon play and
record evidence in `PLAYTEST_NOTES.md`. Compare balance only after mechanic
correctness. Expand the selected classes' other trees before other classes.
The completion gate is verified behavior for the reviewed core/initial-tree
builds on players and companions, a coherent 1-tank/1-healer/3-damage party in
live playtests, and an explicit record of any unresolved source limitations.
Catalog counts, a boss kill, or passing preparation tests are insufficient.
## Source-backed priorities
The following anchors are from the August Vol'Jin capture in
`src/game/coaLiveData.generated.json`. They identify work to verify; they are
not claims that these mechanics are implemented.
- Guardian: Footman's Calling (node 4019, spell 92105) establishes formation
behavior; Vanguard's Shield (34417, 804383) builds stacks through blocks and
auto attacks; Paragon (29969, 706514) transforms Heavy Blow at 10 stacks and
interacts with Brace. Audit formation gates, actor-owned stacks, block events,
threat, and defensive sequencing together.
- Witch Doctor: Cauldron Brewer (4005, 92085), Ingredient: Jungle Shrooms
(12645, 801660), Potion Toss (12646, 801661), and Mixologist (6645, 561069)
establish cauldron/ingredient state, nearby ally effects, and ingredient-based
changes to a targeted heal. Verify recipient, radius, periodic cadence,
ingredient exclusivity/capacity, and healing formulas before adding interactions.
- Barbarian: Decapitate (5744, 804414) requires a target below 35% health and
converts additional Energy into damage; Beheader (6744, 705222) refunds Energy
after an eligible kill; Battle Rhythm (14303, 800193) generates Energy on
ability critical hits. Verify event origin and payment/refund ordering.
- Ranger: Precision Shot (31178, 500075), Hunting Shot (29660, 801191), and
Masterful Archery (7794, 680469) depend on Advantage, Elude, ricochet hits,
and stacking effects. Audit the state and target selection before AI priorities.
- Pyromancer: Ignite (6985, 800791), Combustion (29854, 520884), and Pyroclasm
(7174, 520019) depend on Heat, Embers, and the caster's burning effects on a
specific target. Verify periodic generation, spending, effect counting, and
effect consumption. The August Agonizing Burns/Timed Attacks payload exchange
also requires explicit saved-build review.
Current generated resource profiles and generic effects do not prove these
stateful loops are supported. Unspecified proc timing, missing coefficients,
and unknown server rules remain evidence gaps; never invent their values.
Use the cached Vol'Jin capture and global Spell data described in
[COA_REFERENCE_PIPELINE.md](COA_REFERENCE_PIPELINE.md).
## Repeatable preparation and targeted diagnostics
`src/game/coaFirstPartyRoster.ts` owns the exact roster. The benchmark helper at
`src/game/benchmark/coaFirstParty.ts` owns build selection, companion construction,
and explicitly scoped Balance Lab configurations.
`scripts/coa-first-party/prepare.ts` produces the review inventory and five
active-player configurations, retaining the same party build IDs in each.
```sh
npm run coa:party:prepare -- --list-bosses stormwind-stockade
npm run coa:party:prepare -- --level 60 --boss <exact-key-from-list>
npm run coa:party:test
```
Preparation writes ignored local artifacts to
`artifacts/coa-first-party/level-60/`: `audit.json`, `audit.md`, `config.json`,
and `seat-1.json` through `seat-5.json`. It records the source capture/hash,
legal generated talent allocations, source gaps, and runtime representations.
Every mechanic begins as `needs-review`; mapping is not verification.
It downloads nothing and runs no encounter simulations.
Once an explicit diagnostic is appropriate, the existing runtime consumes a
prepared configuration without changing the ordinary companion pool:
```sh
npx vite-node --mode balance-lab scripts/balance-lab/runtime.ts simulate --config artifacts/coa-first-party/level-60/seat-2.json --output artifacts/coa-first-party/level-60/seat-2-runs.json
```
Only the selected five and explicitly named bosses belong to this milestone's
diagnostics. All five remain **Needs Testing**. Do not change Ready policy,
random/eligible pools, default regression scope, or all-class sweep coverage.
Ordinary live party generation currently uses the Ready WoW pool, including
for a CoA player; a complete CoA party must be configured explicitly.
For implementation changes, run the smallest affected tests plus the existing
Ready-five checks, build, and `npm run release:check`. Record each mechanic's
source, player/companion checks, and live evidence as it is completed.
## Initial implementation and evidence limits
The first catalog fix exposes sourced active Talent entries for these five
classes. Talent Essence purchase type no longer prevents an active spell from
becoming a usable action. The action retains its talent-node/rank gate. DBC
passive flags and rank metadata keep passive Talent nodes on the existing
modifier path; missing DBC rows cannot create a new action. The other 16 classes
retain their previous action catalogs.
This fixes action availability, not the complete effect of each spell. Initial
Potion Toss checks cover its base targeted heal and mana payment for a player
and companion. The follow-up below adds ingredient state and the Frog Bones
rider; other riders and the complete Brewing loop remain work. Decapitate's
target-health gate and Beheader's kill refund are separate mechanics;
additional Energy conversion remains unresolved.
Ranger's primary resource is now Focus, matching its spell costs. Player and
companion checks cover spending, the displayed/authoritative pool, and recovery.
The existing authored 100-point pool and 10-per-second recovery are retained;
this correction does not establish source-verified regeneration or implement
Advantage/Elude.
Brewing has specific evidence limits beyond the node-rank source inventory:
Mojo Beam's capture describes eight seconds while the selected DBC says four;
Spirit Link Idol's tooltip says fourteen seconds while its DBC says 8.5. The
current promoted catalog omits the Loa's Blessing empowerment payloads
802207/802208/802215/802216 and Spirit in a Bottle's referenced
504606/707172 payloads. Resolve those exact references against the local/raw
cache before implementing their full behavior. Zero missing node-rank DBC rows
does not establish that every mentioned payload or server rule is known.
## Kickoff validation and diagnostic baseline
On 2026-10-04, 87 focused tests across 15 files pass, including the exact roster,
learned Talent actions, Potion Toss delivery, Decapitate's health restriction,
Ranger Focus, source scope, and classic catalog preservation. Ready-five checks
pass seven game tests and twenty Python tests. The production build passes
TypeScript, asset audits, bundling, compression, and bundle verification.
`npm run release:check` passes, including untracked files. A before/after digest
also confirms the other 16 CoA action catalogs are unchanged.
The targeted automated baseline uses the same five generated level-60 builds,
seed 1, and Taragaman the Hungerer (`ragefire-chasm/entry-11520`). Each run has a
30-second limit and moves only the active player seat. Results after the Focus
correction are:
| Active player | Outcome | Elapsed seconds | Boss health remaining | Deaths |
| --- | --- | ---: | ---: | ---: |
| Guardian | Time limit | 30.0 | 80,065 | 0 |
| Witch Doctor | Time limit | 30.0 | 79,292 | 0 |
| Barbarian | Defeated | 12.6 | 0 | 0 |
| Ranger | Time limit | 30.0 | 12,782 | 0 |
| Pyromancer | Time limit | 30.0 | 14,724 | 0 |
Raw runs are local ignored artifacts at
`artifacts/coa-first-party/level-60/seat-1-runs.json` through `seat-5-runs.json`.
The original claim that Ranger and Pyromancer companions each cast only three
times was a telemetry error. Damaging companion casts were omitted from the
counter despite damage and decision events showing more activity. The corrected
collector counts release presentations once per cast, including channel pulses
only once. A new Hamhock healer-seat diagnostic records 19 Ranger and 17
Pyromancer companion casts. Ranger still records 32.3% Focus starvation; raw
cast counts do not establish a coherent resource/state rotation. The large
player-seat differences require mechanic investigation before balance changes.
These low-pressure encounters provide limited evidence for tank/healer interactions.
These are explicitly scoped automated diagnostics, with no live browser
playtest or balance certification in this kickoff. All five remain Needs
Testing. New routine diagnostics use Stormwind Stockade: Cellblock Rush
(`bite-sized-stormwind-stockade`) under `TEST_DUNGEON_POLICY.md`; record the
boss selected from the run ID. Full-source Stockade campaigns require explicit
selection. The Taragaman records above remain historical evidence.
## Mechanics and rotation follow-up, 2026-10-05
- `coaGuardianVanguardRuntime.ts` owns learned node 34417's actor-owned Vanguard
state. Source spells 804383/804384 establish one stack per landed normal swing
or block, ten maximum, a refreshed 60-second duration, and 2% less damage from
each magic school per stack. Direct incoming spells use the current mitigation
before consuming one stack. Periodic-tick consumption is unresolved and is
excluded. Player and companion event hooks use the same state transition.
- `coaWitchDoctorBrewingRuntime.ts` owns persistent ingredient markers and the
one-ingredient capacity, raised to two by learned Mixologist node 6645. An
ingredient already present may refresh; an additional ingredient at capacity
fails before payment. Replacement/removal behavior is not specified by the
captured evidence. Frog Bones 801663 no longer creates the importer's bogus
one-second caster shield. It retains its 1.5-second cauldron pulse. Potion Toss
801661 adds the shield from global spell 802971 to its selected ally only when
that caster owns an active Frog Bones marker: eight seconds, base 100, five
points per level from level ten, 35% Spirit and 80% bonus healing. Other
ingredient markers do not establish their unfinished Potion Toss riders.
- `coaBarbarianExecuteRuntime.ts` also owns learned Beheader node 6744's exact
Decapitate kill refund: 100% of maximum Energy after an effective killing hit,
clamped to the pool maximum. Failed, nonlethal and unrelated hits do not refund.
The additional-Energy damage conversion has no verified ratio in this slice.
Its generic weapon-damage projection also needs review: separate DBC weapon
effects must not be treated as two independent weapon hits.
- Pyromancer Ignite's selected-enemy implicit target takes precedence over its
DBC radius metadata. Both tree and progression variants use unit targeting;
nearby enemies no longer receive the selected enemy's burn.
- Chosen-five unit-target periodic maintenance compares ability, caster,
recipient and positive remaining duration. A burn or HoT on one actor no
longer blocks applying that spell to a different actor. This correction does
not author speculative class priority lists or clipping windows. Mojo Beam's
incidental caster aura no longer redirects its friendly unit heal to the
caster; the scorer selects the injured ally and checks that ally's own HoT.
An actual companion channel check verifies Mana payment and the first pulse
on the injured Vanguard ally. It does not resolve Mojo Beam's duration conflict.
The companion Potion Toss rider check primes its actor-owned ingredient marker
explicitly. Default healthy companion AI does not prepare its cauldron; authored
ingredient preparation and selection remain a rotation gap. Loa's Brew winning
one injured-ally fixture does not, by itself, establish a wrong healing priority.
Formation/Paragon, full Brewing riders and payloads, Decapitate's Energy
conversion/Battle Rhythm, Ranger Advantage/Elude, Pyromancer Heat/Embers and
reviewed talent allocations remain the next mechanics work. All five remain
Needs Testing. Automated checks do not replace live party playtests.
The follow-up's explicitly scoped Stockade/Hamhock diagnostic retains level 60,
seed 1, a 30-second limit and the same five generated builds in each seat:
| Active player | Outcome | Elapsed seconds | Boss health remaining | Deaths |
| --- | --- | ---: | ---: | ---: |
| Guardian | Time limit | 30.0 | 80,815 | 0 |
| Witch Doctor | Time limit | 30.0 | 77,898 | 0 |
| Barbarian | Defeated | 13.6 | 0 | 0 |
| Ranger | Time limit | 30.0 | 28,443 | 0 |
| Pyromancer | Defeated | 27.8 | 0 | 0 |
Raw runs are ignored local artifacts at
`artifacts/coa-first-party/stockade-2026-10-05/seat-1-after.json` through
`seat-5-after.json`; seats two/four also retain before runs. The final healer-seat
run records 19 Ranger and 16 Pyromancer companion casts, with Ranger still
32.3% Focus-starved. Correct source behavior can change damage and timing;
these outcomes do not establish balance, authored allocations, or full-class
completion. Low encounter pressure limits healer/tank conclusions. No live
browser playtest was performed in this mechanics follow-up.
Focused validation passes 126 tests across 19 directly affected files, including
the helper, public scorer and actual player/companion behavior checks. Ready-five
compatibility passes seven Vitest and twenty Python tests. The generated runtime
and UI changes are limited to two Pyromancer Ignite actions; the other twenty
class records, resource profiles and triggered payloads are preserved.
The final production build passes TypeScript, asset audits, bundling, static
compression and release-bundle verification. `npm run release:check` passes,
including untracked files. The canonical CoA vault note is updated separately.
## Brewing integration, 2026-10-05
`coaWitchDoctorBrewingAi.ts` owns an authored companion preparation policy.
`partyRuntime.ts::choosePartySupportIntent` prepares learned Frog Bones when a
Brewing healer has Brewer and Potion Toss, every party member/player is at
least 90% healthy, and no resurrection, dispel or engaged-enemy cast is pending.
Normal readiness, Mana, target and capacity checks still precede payment. It
preserves an existing full cauldron and does not refresh an existing own Frog
Bones marker. This is a conservative gameplay policy, not a sourced optimal
rotation. Other ingredient selection remains unfinished.
`partyAbilityAi.ts` projects the caster's current Brewing effects before
scoring heals. Ingredient casts are excluded from the ordinary Brewing healer
rotation so they cannot displace healing or repeatedly refill the cauldron.
Actual idle companion tests prepare through normal selection and payment,
then heal and shield an injured player with Potion Toss, without seeding an
in-flight cast or priming an ingredient marker.
Splash Potion node 7128/spell 802710 is now a friendly ground action in source
generation and the runtime/UI catalogs. Its DBC destination targets 87/31 and
captured tooltip establish a location, 40-yard range, 10-yard radius and up to
eight allies. Its base heal centers on that destination. The cast projection
suppresses the importer's unconditional flattened ingredient and SLS payloads;
only an owned, live Frog Bones marker adds verified 803699's reduced absorb:
eight seconds, base 25 and one point per level from level 15. Player and NPC
tests check nearby recipients, excluded distant allies, no inactive riders,
and destination validation before payment. The player's previous radius shield
branch centered on the caster; the Splash-specific path now uses the same
effect-scoped ground center as its healing. Existing other spell paths retain
their behavior.
Jungle Shrooms 802973's exact Spirit scaling, Fish Oil 802969's aura decoding,
Bloodthistle 802975/803287's proc and 0.5-second internal cooldown, and the
803275 SLS ingredient-combination chain remain unresolved. Their raw source
records are retained; missing runtime semantics do not grant every rider.
The Guardian audit identifies the next import boundary. August Vol'Jin node
4019/spell 92105 establishes 10% self mitigation while Tower or Line Formation
is active, with no numeric threat multiplier. Global spells 800317 and 803130
would create self-owned aura identities `coa:800317:effect:0:aura:87` and
`coa:803130:effect:0:aura:232`, but neither action is present in the promoted
tree/progression/runtime catalog. Mitigation cannot honestly use an assumed
formation flag. Paragon 29969/706514 has a description conflict: the August
builder changes Heavy Blow to Paragon Smash, while the promoted primary text
for 706516 still describes Tower/Bastion. The later formation audit below finds
compatible secondary text and child payloads. Import formation actions and
preserve the source discrepancy when wiring the conditional mechanics. See the cached Guardian JSON and builder in
`data/coa-reference/cache/archive-5078f9ac2254/generation-fa16afec-8f11-4eab-98ab-b6441304fab7/`
and global snapshot `e86031775dfac7e336361087c50ca23a0a7a86c36a760c85803bee4bcdb89351`.
Rotation policy is `playerbots-inspired-v10-coa-brewing-preparation`. The same
five level-60 builds, seed 1, Hamhock and 30-second limit produce:
| Active player | Outcome | Elapsed seconds | Boss health remaining | Deaths |
| --- | --- | ---: | ---: | ---: |
| Guardian | Time limit | 30.0 | 80,007 | 0 |
| Witch Doctor | Time limit | 30.0 | 77,898 | 0 |
| Barbarian | Defeated | 13.6 | 0 | 0 |
| Ranger | Time limit | 30.0 | 28,599 | 0 |
| Pyromancer | Defeated | 24.8 | 0 | 0 |
The Guardian-seat companion records one naturally selected Frog Bones cast.
Raw evidence is preserved separately at ignored
`artifacts/coa-first-party/stockade-integration-2026-10-05/seat-1.json` through
`seat-5.json`. Encounter pressure is low; the healer deals substantial damage,
and these results establish neither balance nor a complete healing rotation.
All five remain Needs Testing. No live browser playtest was performed.
Focused validation passes 37 tests across eight directly affected files;
Ready-five compatibility passes seven Vitest and twenty Python tests. The new
generated catalog change is one Witch Doctor Splash action in each runtime/UI
catalog; the other twenty class records, resource profiles and triggered
payloads are preserved. No recrawl or download was needed.
The final production build passes TypeScript, asset audits, bundling, static
compression and release-bundle verification. `npm run release:check` passes,
including untracked files; the canonical CoA vault note is updated separately.
## Decapitate strike integration and Guardian audit, 2026-10-05
`coaBarbarianWeaponDamageRuntime.ts` projects only tree node 5744/spell 804414
as one normalized weapon strike. The imported effects previously emitted two
independent damage events. The August Vol'Jin tooltip gives the formula:
`27 + 2.2 * (weapon mean + attack power / 14 * normalized speed)`. Explicit
equipped-item classification supplies the standard normalized speed: 3.3 seconds
for two-handed melee weapons, 1.7 for daggers, and 2.4 for other one-handed
melee weapons. Actual swing speed is used only to undo the existing weapon-DPS
conversion. An unknown weapon classification retains the imported fallback.
The helper is used before player execution in `combatStore.ts`, companion
execution in `partyRuntime.ts`, companion scoring in `partyAbilityAi.ts`, and
active-seat scoring in `benchmark/benchmarkController.ts`. Applying it repeatedly
preserves a single strike. It retains identity, cost, targeting, the below-35%
health gate, and Beheader's successful-kill refund. The additional Energy
conversion ratio remains unknown and is not implemented.
The historical generic AzerothCore weapon-effect sequence adds the flat bonus
before applying the percentage, which would also multiply 27. The custom CoA
server script is unavailable; this projection follows the explicit CoA tooltip's
flat bonus outside the percentage. This source interpretation remains recorded
in the helper and does not claim verification against the live server.
The Guardian audit now distinguishes acquisition from payload reconciliation.
Tower 800317 and Line 803130 carry trainer source 6, levels 4/20, but lack a
current tree node or ranked progression chain. They need an explicit rankless
trainer import path and formation-specific effect handling. No formation state
was seeded. Paragon stack spell 706516's secondary field 187 matches the August
Heavy Blow/Paragon Smash description, and children 802629/803432 support its
damage and block/Brace effects. The older primary Tower/Bastion description
is preserved as a conflict. Exact IDs, raw-field provenance, modifiers and
remaining acquisition boundaries are in
`docs/COA_GUARDIAN_FORMATION_AUDIT_2026-10-05.md`.
Rotation policy is `playerbots-inspired-v11-coa-decapitate-strike`. The explicitly
selected five builds run at level 60, seed 1, with a 30-second limit against
Cellblock Rush's catalog-template boss, Hamhock
(`bite-sized-stormwind-stockade/entry-1717`):
| Active player | Outcome | Elapsed seconds | Boss health remaining | Deaths |
| --- | --- | ---: | ---: | ---: |
| Guardian | Time limit | 30.0 | 80,007 | 0 |
| Witch Doctor | Time limit | 30.0 | 77,898 | 0 |
| Barbarian | Defeated | 12.8 | 0 | 0 |
| Ranger | Time limit | 30.0 | 29,396 | 0 |
| Pyromancer | Defeated | 24.8 | 0 | 0 |
These are isolated headless boss-room diagnostics, not a live dungeon clear.
The boss identity comes from the registered Cellblock Rush template; a fresh
live run can select a different boss. Raw configs/results are ignored local
artifacts at `artifacts/coa-first-party/stockade-decapitate-2026-10-05/`.
The final Barbarian active-seat scorer chooses other attacks in this run; its
Decapitate count is zero. Deterministic regression fixtures separately prove
one correctly calculated damage event through actual player and NPC casts.
Damage/selection changes do not certify balance, and encounter pressure remains
too low to establish tank/healer completeness. All five remain Needs Testing.
Focused validation passes 22 tests across five directly affected files,
including the actual player/NPC strike checks and existing execute/Beheader
regressions. Ready-five compatibility passes seven Vitest and twenty Python
tests. This pass changes no generated catalog records or readiness pools.
The final production build passes TypeScript, asset audits, bundling, static
compression and release-bundle verification. `npm run release:check` passes,
including untracked files; the canonical CoA vault note is updated separately.
## Guardian formations and Paragon integration, 2026-10-05
Tower Formation 800317 and Line Formation 803130 now have an explicit rankless
trainer import path in `coaAbilityCatalog.ts`, constrained to the two sourced
Guardian/class-18 rows with trainer source 6, valid levels and matching DBC
identities. They learn at levels 4 and 20 through the game's existing automatic
level-learning model. No tree grant or named trainer is invented. The generated
runtime and UI catalog changes are limited to Guardian records.
`coaGuardianFormationRuntime.ts` replaces the flattened source effects with one
owned self aura per cast. Tower gives +10 percentage points of block, adds half
of the actual shield item's armor and reduces outgoing damage by 10%. Line
adds 15% movement speed and reduces roots by 25%. Aura 232/misc 7 identifies
Root; the broader tooltip wording remains a source conflict, so other control
types retain their duration. Footman's Calling node 4019 adds 10% taken-damage
reduction only while an own live form is active. Projection uses current talent
ranks, equipment and health, preventing borrowed/expired markers and recomputing
shield armor after equipment changes. No numeric threat grant is assumed.
Switching replaces the other form through an authored exclusive group; source
categories 708/709 do not prove exclusivity. Toggle-off remains unfinished.
`coaGuardianParagonRuntime.ts` follows August Vol'Jin node 29969/706514,
706516's compatible secondary text and linked payloads. Heavy Blow adds three
stacks on successful cast; a block adds one with a 500 ms stack-trigger internal
cooldown. Stacks last ten seconds and cap at ten. Readiness 707138 grants no
block bonus. While ready, Heavy Blow's existing action slot, identity, cost,
talent gate and cooldown project to Paragon Smash: 144 + 37% AP in an 8-yard
self circle, confirmed by local SpellRadius.dbc row 14. A successful Smash
creates the separate ten-second +10-point block buff with five block charges.
Each block during that buff consumes a charge and reduces an active Brace
cooldown by two seconds. Companion authority and its mirrored member receive
the same reduction. No unverified stack-consumption/reset rule is introduced;
a qualifying event can reestablish readiness after its previous window expires.
The stale primary Tower/Bastion text remains documented in the source audit.
Player execution, companion execution/scoring, active-seat benchmarking and HUD
use the shared projection. The HUD displays Smash in the Heavy Blow slot during
readiness. Both player and companion movement consume owned Line speed.
Vanguard companions prepare learned Tower through ordinary readiness, targeting
and resource payment and preserve an existing Line. Formation preparation
respects `nextActionAt`, so a future preparation decision does not suppress
normal attacks. Cast/block fixtures prove player and companion paths; they use
explicit block-probability fixtures to make combat outcomes deterministic.
The ready-Smash priority is an authored rotation policy: priority 7,500 only
for a Vanguard tank at or above 55% health; injured, unknown-health and other
actors retain the existing fallback preference. The public companion scorer
uses ordinary learned, ready candidates and chooses Smash over routine Ballad
maintenance. Existing low-health mitigation and urgent reactive taunt/interrupt
scores remain ahead of it. This is a gameplay preference, not a source-derived
optimal rotation.
Rotation policy is `playerbots-inspired-v12-coa-guardian-formations-paragon`.
The generated five builds at level 60, seed 1, with a 30-second limit against
Cellblock Rush's catalog-template Hamhock
(`bite-sized-stormwind-stockade/entry-1717`) produce:
| Active player | Outcome | Elapsed seconds | Boss health remaining | Deaths |
| --- | --- | ---: | ---: | ---: |
| Guardian | Time limit | 30.0 | 81,106 | 0 |
| Witch Doctor | Time limit | 30.0 | 76,687 | 0 |
| Barbarian | Defeated | 12.8 | 0 | 0 |
| Ranger | Time limit | 30.0 | 23,870 | 0 |
| Pyromancer | Defeated | 24.8 | 0 | 0 |
Each companion-Guardian seat records one naturally selected Tower cast. The
active-player benchmark records no Tower cast; manual player casting is covered
by actual cast fixtures and the browser diagnostic. These
are isolated headless diagnostics at ignored
`artifacts/coa-first-party/stockade-guardian-2026-10-05/`, not live dungeon clears.
The role-weighted Guardian allocation does not learn Paragon/Heavy Blow, so
these five results do not establish Smash selection. Incoming damage is low;
all five remain Needs Testing and no random/readiness pool changed.
Focused validation passes 66 unique tests across fifteen directly affected CoA
and input files, including actual player/companion formation and Paragon casts, incoming
root handling, shield armor/Footman's Calling, block charges/Brace reduction,
unrestricted companion scoring and prior Brewing/Splash/weapon-strike paths.
Ready-five compatibility passes seven Vitest and twenty Python tests. Avatar
checks pass 56 tests across eleven files. Narrow compatibility checks for the
shared workspace's boss guide, disarm metadata/runtime and extra-attack helper
pass seventeen tests; compatibility fixes preserve those existing behaviors.
The final production build passes TypeScript, asset audits, Vite bundling,
static compression and release-bundle verification. During verification,
concurrent enemy-runtime changes briefly duplicated/removed their interface
fields and concurrent bootstrap runs collided on an exclusive object write;
final validation uses the successful completed build. The final creature weapon
state declarations share one typed interface, preserving runtime behavior.
The isolated live harness uses an explicit, runtime-normalized level-60 Guardian
variant learning Paragon and Heavy Blow alongside Footman's Calling, Brace and
Vanguard's Shield. It resolves the public catalog preloader and resource API's
minified export aliases from source-matched bundle AST, loads the five class
catalogs before entry, and verifies their resource profiles. Switching characters
cannot preload a whole party persistently because the app reloads its memory
when the entered character changes. The harness therefore installs a scoped
pre-entry PartyBridge initialization fixture, calls the normal initializer and
substitutes the prepared companions before actor synchronization. It leaves
readiness/random pools unchanged and seeds no combat/proc state. A selectable
first-party preset in the game UI remains separate work.
Live entry exposed two startup gaps and supplied the final regressions.
`combatRotation.ts::precombatPreparationEffects` now excludes exact Guardian
formation spells from generic free aura preparation: initial entry has no form,
player casting pays normally, companion preparation casts normally, and later
preparation cannot add a second raw form or replace a chosen Line.
`actionBindings.ts::normalizeActionBindings` separates default assignment order
from an optional explicit allowlist. `combatStore.ts::initializeCharacter`
validates saved slots against all nonpassive class actions, then retains the
existing unlearned-talent filter. The learned Heavy Blow talent action survives
entry in its saved slot, while unlearned and unknown actions are rejected.
The shared `dist/assets` directory became locked during rebuild. Final verification
uses an isolated output at
`artifacts/coa-first-party/stockade-guardian-2026-10-05/dist-final`: prebuild and
asset audits passed, then the same npm build command ran with lifecycle hooks
skipped and an explicit output override; compression and release-bundle checks
ran explicitly against that output. The live harness accepts a confined `--dist`
path and records the directory/bundle assets actually tested.
The final 180-second browser diagnostic completes on the isolated production
bundle at `artifacts/playtest/coa-guardian-formations/20261006-011259958/`.
Normal offline creation, Button Assignments, Cellblock selection/download and
Tank entry are preserved; the exact companion composition is the explicitly
recorded pre-entry fixture. Entry verifies level 60, all five catalogs, no seeded
formation and the saved Heavy Blow R2 slot. Real action-bar clicks cast Tower,
Line and Tower again, each leaving only its own projected form. The first Tower
reduces Energy from 100 to 83; this legal build's cost modifiers resolve the
base 20 cost to 17, with normal regeneration between later casts.
The fresh run selects Dextren Ward (`entry-1663`, `creature-79116`), confirmed
by its intro card. Screenshot 02 is a countdown overlay because the initial
detachment wait raced the intro's appearance; screenshots 03/04/06 provide the
actual in-dungeon evidence. The route explores about 8 m near the entrance,
with 5.74 m net displacement, full player/party health and no observed boss
actor. It records only the three formation casts, no natural Paragon ready/Smash
marker and no healing/combat pressure. It does not establish a clear, balanced
party, live Smash proc or complete tank/healer rotation. The actual proc/block/
Brace and unmasked scorer coverage comes from the focused regression fixtures.
Reviewed the roster body/shield capture and in-dungeon captures: the player
body and equipped shield/weapon silhouettes render, while the clustered party
and large temporary gold effects obscure some companions. Heavy Blow remains
visible in its saved R2 slot at the endpoint. Browser exceptions are zero;
one console 404 is unclassified, with no failed requests or HTTP errors in
the harness's recorded request scope. These visual and request limitations
remain in the live evidence. All five stay Needs Testing. The source/cast fixes,
scoped diagnostic harness, milestone, source audit and canonical CoA vault note
are updated together.
`npm run release:check` passes, including untracked files. The Git index is
unchanged; no commit, deployment or readiness promotion was performed.
@@ -0,0 +1,139 @@
# Guardian formation and Paragon source audit, 2026-10-05
The original read-only audit below bounded the Vanguard integration. The
implementation follow-up records the resulting runtime contracts; the selected
five CoA builds remain Needs Testing.
## Action acquisition
The August 12, 2026 Vol'Jin builder capture has 161 Guardian nodes and no node
for Tower Formation 800317 or Guardian Line Formation 803130. Footman's Calling
4019, The Green Tower 30060, Banner Boy 29798, and Press the Line! 6817 reference
them in descriptions; references are not learn-spell grants.
The separate July 25 class-spell metadata in `src/game/coaLiveData.generated.json`
marks both spells class 18 with `sourceIds: [6]`. `scripts/sync-ascension-coa.mjs`
maps source 6 to the trainer flag when building ranked progression chains.
These two spells are rankless, have no progression chain, and are absent from
the promoted action catalog. Tower's level is 4 with Talent/tab 7 metadata;
Line's level is 20 with no advancement type. This is evidence for a trainer
channel, but the current import path needs explicit rankless trainer support.
There is no captured named trainer, exact unlock row, or current tree grant.
## Formation effects
| Spell | Cost / duration | Self effects | Integration requirement |
| --- | --- | --- | --- |
| Tower 800317 | 20 Energy / indefinite | Aura 87, base 0; aura 142, +50; aura 79, -10 | Resolve linked +10% block from 803431 effect 3; implement shield armor contribution separately from generic resistance; retain -10% outgoing damage. |
| Line 803130 | 20 Energy / indefinite | Aura 232, -25, misc 7; aura 79, 0; aura 31, +15 | Implement the captioned control-duration reduction and movement; apply the conditional Vanguard mitigation through a real owned form. |
Both have no cast time or individual recovery. Their categories are 708 and
709; these do not establish mutual exclusion or toggle-off behavior. The source
does not provide a cancellation/grant relationship between them. Tower's armor
caption modifies the shield contribution, so applying +50% total armor or
physical resistance would be incorrect. Generic aura conversion also leaves
Line's aura 232 unsupported.
Footman's Calling 4019/92105 establishes -10% self damage while Tower or Line is
active. A future runtime check must require the caster's own live self aura:
`coa:800317:effect:0:aura:87` or `coa:803130:effect:0:aura:232`. Spell 92105 has no
trigger grant. Referenced 807728 is a separate tank-stance payload, not a spell
granted by that passive; its threat value cannot be assumed active merely from
learning Footman's Calling. Do not substitute Tower Stance 803907, visual
803941, or Line SLS 803151/803690 for the acquisition of the two real actions.
## Paragon reconciliation
The August live node 29969/706514 describes stacks from blocking, a ten-stack
Heavy Blow to Paragon Smash transformation, and three stacks from Heavy Blow.
The block trigger is limited to once per 0.5 seconds, and stacks last 10 seconds.
Smash deals 144 + 37% AP to nearby enemies and adds +10% block; blocking reduces
Brace's cooldown by two seconds, for five blocks or ten seconds.
The linked stack spell 706516 has inconsistent text fields. Its primary field
170 still describes the older Tower/Bastion transformation. Field 187 instead
describes Heavy Blow to Paragon Smash, matching the live node. Archive children
802629 (damage) and 803432 (buff) support the Smash damage and block/cooldown
payload. This narrows the discrepancy to the stale primary description rather
than proving the old transformation is the intended current behavior. The live
node and compatible child payload should guide the next implementation; keep
the conflicting primary text as evidence.
The active sync prefers localized field 170 and falls back to field 187 only
when 170 is empty. Its promoted primary-only description therefore loses this
useful secondary text. No gameplay behavior changed in this audit.
## Offline provenance
- Builder and tree: `data/coa-reference/cache/archive-5078f9ac2254/generation-fa16afec-8f11-4eab-98ab-b6441304fab7/`,
`raw/talents/coa-builder-voljin.html`, `raw/talents/_fetch.json`, and
`data/talents/coa/Guardian.json`. The fetch record gives capture time
`2026-08-12T21:02:51+00:00` and SHA-256
`41a6ccd393c0648ae2b1fdc34fe94955d4fd13c0cd59040ad3860e64a8ff6c7a`.
- Patch-T raw spell shards: under the same archive's `spell-base/shards/`.
Stack spell 706516 is in `00700000-00709999.jsonl.gz`, not a 7-million-ID shard.
Formation/helper rows use `00803000-00803999.jsonl.gz`; 802629 uses
`00802000-00802999.jsonl.gz`; 807728 uses `00807000-00807999.jsonl.gz`.
`spell-base/Spell.colinfo.json` maps the positional fields.
- July global snapshot: `data/coa-reference/snapshots/e86031775dfac7e336361087c50ca23a0a7a86c36a760c85803bee4bcdb89351/reference.json`.
All of the effect and text reconciliation above used cached/local records.
It does not require recrawling the class database or downloading the client.
## Implementation follow-up, 2026-10-05
`coaAbilityCatalog.ts` now imports only the two evidenced rankless Guardian
trainer actions through a class/source/level/DBC-identity allowlist. Tower is
learned at level 4 and Line at level 20 under HealerMan's existing automatic
level-learning model. A named trainer interaction is not reconstructed. Only
Guardian records were regenerated in the runtime and UI catalogs.
`coaGuardianFormationRuntime.ts` projects each cast into one permanent,
caster-owned self aura. Tower adds 10 percentage points of block, 50% of the
actual equipped shield item's armor, and -10% outgoing damage. Line adds 15%
movement speed and reduces roots by 25%: aura 232's misc value 7 identifies
Root, so the caption's broader control wording is not applied to every control
type. Footman's Calling adds -10% taken damage only while either own live form
is active. Projection recomputes current talent/equipment contributions without
requiring a recast; borrowed, expired and other-class markers do not qualify.
No numerical threat multiplier is inferred. A shared exclusive group makes
switching replace the old form as an explicit authored game policy; the source
categories do not prove this behavior. Toggle-off remains unimplemented.
`coaGuardianParagonRuntime.ts` uses the August live node and compatible secondary
text. Actual Heavy Blow successes add three stacks and actual blocks add one,
with a 500 ms block-stack internal cooldown and 10-second stack lifetime.
At ten stacks, 707138 represents readiness only. Heavy Blow retains its action
identity, talent gate, cost and cooldown while projecting to an 8-yard self
area strike for 144 + 37% AP. SpellRadius.dbc row 14 in the local patch-S
extraction confirms the 8-yard radius. Only a successful Smash creates 803432's
10-second +10-point block buff with five block charges. Each actual block while
that buff is live consumes one charge and reduces an active Brace cooldown by
two seconds for the player or companion authority and its mirrored member.
Readiness itself grants no defensive bonus. Stack reset/consumption is not
encoded in the inspected source, so no reset rule is invented; a later qualifying
event can establish readiness again after its prior window expires.
The player executor, companion executor/scorer, benchmark selector and HUD use
the same cast projection. Player and party movement consume the owned Line
modifier. Vanguard companions prepare Tower through normal learned-action,
readiness, target and resource checks, preserving an already chosen Line.
Actual cast/block integration fixtures and the source conflicts above remain
separate from balance certification. Live results and required checks are
recorded in `docs/COA_FIRST_PARTY_MILESTONE.md` and `PLAYTEST_NOTES.md`.
Companion Smash selection is explicitly authored: priority 7,500 for Vanguard
tanks at or above 55% health, fallback preference 40 otherwise. Unmasked public
scorer checks choose ready Smash over routine Ballad when healthy, retain real
mitigation when injured, and preserve urgent taunt/interrupt scores. The exact
source optimal rotation remains unknown. Focused Guardian/helper/party checks,
Ready-five compatibility and the production build pass; see the milestone for
complete validation scope and the bounded live evidence.
Actual browser entry also exposed generic free preparation of both raw forms
and loss of a saved Heavy Blow talent binding. Final regressions cover the
source fixes: generic precombat effect selection excludes the two real forms,
while character initialization validates saved nonpassive class actions against
a separate allowlist before rejecting unlearned talent slots. These fixes retain
normal resource payment, the authored exclusive group and the original default
bar order. The selected five remain Needs Testing.
+164
View File
@@ -0,0 +1,164 @@
# CoA offline reference pipeline
The reference pipeline prepares source evidence for implementing all 21 Conquest
of Azeroth classes. It reads existing client files first, generates a searchable
dataset, and compares source versions. An explicit offline promotion updates the
active CoA catalogs. CoA remains Needs Testing; source coverage does not certify
class mechanics or balance.
## Sources and version boundaries
The default source pair is `H:/resources/client` and `H:/LadiksMPQEditor` when both
exist. Otherwise the pipeline uses the project's sibling `resources/client` and
`LadiksMPQEditor` directories together. In this workspace those are under
`F:/Projects`. To choose another installation, supply both roots explicitly:
```powershell
npm run coa:reference:inventory -- --client-root H:/resources/client --extracted-root H:/LadiksMPQEditor
npm run coa:reference:build -- --client-root H:/resources/client --extracted-root H:/LadiksMPQEditor
```
The frozen July trees come from
`data/coa-reference/baselines/coa-july-2026-07-25.json.gz`. Before the first
promotion, the original active catalog is preserved losslessly in that file.
Historical reference builds keep using it after active catalog updates. Spell evidence
comes from the extracted base-client tables under `client-current`: global
`patch-T` Spell, `patch-M` class and skill metadata, and `patch-S` supporting
tables. Client `Data/Content` contributes advancement and rank evidence. Relevant
sources receive hashes and version/source labels. Original files stay intact.
July class-spell references also seed identities, including starter spells that
are absent from talent trees and progression chains. Their old DBC values are
not imported. Ownership follows global trigger/effect-168 links so the selective
spell fetch and promotion cover linked payloads in the same CoA scope.
The previous importer preferred the Area 52 `patch-D` overlay. The extraction's README
calls those effective CoA sources, while the external datamine identifies them as
Free-Pick's overlay and uses the base-client chain for CoA. The new reference
retains this disagreement as audit evidence. The combined live importer now
selects global Spell/SkillLineAbility tables for CoA and preserves the existing
Area 52 preference for classic classes. Shared spell IDs have separate CoA
wrappers; classic spell resolution and its triggered fallback remain isolated.
The optional external source is `srhinos/coa-datamine` at commit
`5078f9ac22541c45c17a866c23aac6c12073de23`. Its published talent capture is dated
August 12, 2026. It is a distinct source version applied only by the explicit
promotion command. A surviving API or capture labeled `live` describes source
availability/content at capture time, not the current availability of a realm.
The explicit supplement fetch downloads the pinned talent capture, all 21 derived
talent-tree records, and their identity/provenance metadata. It does not download
the full client extraction or game assets. Git blob hashes and the
capture's published SHA-256 verify the files. Valid cached files are reused, and
interrupted downloads resume at file boundaries. No Exiles crawling is performed.
## Offline active-catalog promotion
```powershell
npm run coa:reference:fetch
npm run coa:reference:fetch:spells
npm run coa:reference:promote
npm run coa:catalogs:refresh
```
The spell fetch is an explicit, selective download of pinned global BASE raw
shards needed for spell IDs absent from the local global table. It includes
linked payloads and verifies the stored shard hashes. It never selects the
archive's Area 52 table. Unresolved old progression ranks retain their identities
and are reported as gaps.
Promotion reads only verified caches and local files. It resolves React Flight
text references in the captured builder before normalizing nodes, filters empty
metadata tabs from playable trees, and checks preservation before atomically
replacing `src/game/coaLiveData.generated.json`. The machine-readable result is
`data/coa-reference/promotion-report.json`. A failed check retains the active
catalog. Repeating promotion with the same inputs produces identical bytes.
Existing `coa-entry-*`, `coa-tree-*`, tree IDs, and progression-chain IDs survive.
Saved talent ranks still follow the normal clamping rules when the captured
maximum rank decreases. An existing node ID can carry a revised effect: August
exchanges the spell payloads of Pyromancer's Agonizing Burns/Timed Attacks and
Cultist's Dark Infusion/Darkward. Saves have no capture-version field, so numeric
ID preservation does not preserve the old effect. Review affected builds after
updating. Existing classic spell records, chains, and generated abilities are
preserved and checked separately.
The refresh command regenerates CoA runtime data and its class shards, resolves
triggered spells from global data, and exports missing icons. It preserves the
existing non-CoA talent records and UI shards.
## Build, search, and audit
```powershell
npm run coa:reference:inventory
npm run coa:reference:fetch
npm run coa:reference:build
npm run coa:reference:audit
npm run coa:reference:lookup -- --class barbarian --tree Brutality --limit 5
npm run coa:reference:lookup -- --class barbarian --ability "Ancestral Strike" --limit 5
npm run coa:reference:lookup -- --spell 800380 --limit 5
```
Fetching is optional and explicit. Build, audit, and lookup work offline. A build
without the archive produces a local-only reference and identifies the missing
comparison. Run fetch and then build to add it. `--refresh` is supported only by
fetch, which revalidates the same pinned revision rather than choosing a new one.
`--output-root PATH` chooses a separate reference output directory; `--cache-root
PATH` chooses the supplemental cache. Defaults are `data/coa-reference` and its
`cache` subdirectory. Lookup accepts numeric class IDs or HealerMan class names,
tree names/IDs, spell IDs, and case-insensitive ability-name fragments. Each result
collection is limited to 20 by default; use `--limit` between 1 and 1000.
Class and tree searches include linked spell ranks and triggered spell dependencies;
those dependencies are not presented as learned abilities.
Build prints the path to the readable audit. The corresponding `audit.json`
contains detailed machine-readable findings. `reference.json` preserves nodes,
spell data, rank relationships, class catalogs, source evidence, and unresolved
relationships. Class aliases are tied to numeric class IDs, so legacy names such
as DemonHunter, Monk, and SonOfArugal do not create extra playable classes.
The report inventories each class, compares July and August nodes/trees, compares
local base spell evidence with the previous imported values, and identifies
runtime-catalog mappings. A mapping is not proof that a talent mechanic works.
The backlog prioritizes source conflicts and identity gaps before bespoke combat
behavior, player/companion integration, UI verification, and targeted balance work.
## Integrity and limitations
Snapshots are content-addressed and immutable. Build writes and verifies all
files before replacing `current.json`. Failed builds leave the last valid
snapshot selected. Rebuilding unchanged sources produces the same snapshot ID.
Audit and lookup verify the selected snapshot's manifest before reading it.
If a source file is malformed or a downloaded cache file fails its checksum, the
command stops with the affected source identified. Restore the original source
or rerun the explicit fetch before rebuilding. Missing spell/dependency evidence
is reported as a coverage gap rather than filled with speculative values.
An existing immutable snapshot with damaged files is rejected. To regenerate it
without changing the damaged evidence, build with a fresh `--output-root` and
point `--cache-root` at the existing verified cache.
Client descriptions, effect fields, and identity joins have different certainty.
The dataset preserves that evidence; it does not invent server-side base stats,
proc timing/rates, missing coefficients, or acquisition rules. Name matches alone
do not establish an exact rank identity. CAD catalog presence alone does not prove
that an ability was trainable in the captured game version.
The promoted trees and spell evidence provide the foundation for class mechanic
implementation. Bespoke procs, resource behavior, acquisition rules, and balance
still require targeted class work before promotion from Needs Testing.
## Validation
```powershell
npm run coa:reference:test
npx vitest run src/game/coaLiveCatalog.test.ts src/game/coaAbilityCatalog.test.ts src/game/coaAbilityCatalogLoader.test.ts src/game/coaSourceScope.test.ts src/game/coaPromotionPreservation.test.ts src/game/talentCatalog.test.ts
npm run release:check
```
Focused pipeline tests cover malformed inputs, source pairing/selection, missing
relationships, independent version comparison, cache integrity/resume, immutable
snapshot publication, and offline lookup. No full test suite or all-class balance
sweep is required for this development-reference change.
@@ -0,0 +1,168 @@
# Control and utility continuation — 2026-10-06
Lichborne now uses exact source-backed player/companion cast allowances and
named-shout purge. Kick and Pummel join Shield Bash's source-bound ordinary-NPC
full blocking. Player weapon autos respect pacify. Deterrence's complete linked
source package is audited; missing runtime inputs remain explicit.
## Implemented behavior
- `enemyControlImmunityPurge.ts` binds Lichborne 49039 to its selected WoW335
identity, class, retained raw attributes and three Aura77 scalar signatures.
Explicit fear/stun/confuse cast permissions are separate from purge. Player
and configured companion casts remove only the four named FEAR-mechanic
shout auras, including 20511's stun/rider. Known generic fear/stun/confuse can
permit Lichborne but remain active and keep the actor controlled. Unknown
source controls and unsupported generic sleep fail closed. Berserker Rage
retains its narrower behavior. Existing Fear/Sleep immunity metadata is
consumed; Charm is source-proven but has no runtime immunity value.
- `partyRuntime.ts` selects a learned, source-proven escape ability for its
owner, retaining target validity, costs and cooldowns. Lichborne's source
GCD is zero: it neither waits for nor clears another active GCD. Retained
action-blocking control keeps the companion holding.
- `enemyUtilitySpellBlocking.ts` binds exact WoW335 Shield Bash 72, Kick 1766
and Pummel 6552 to identity/class/profile/raw metadata and the complete
projected effects. Only source-bound ability validation reconstructs the
two audited custom bits; an unbound raw disposition without proof falls back.
Foreign profiles/ranks, modified effects/wrappers, native actors/targets and
nonordinary recipients cannot borrow the contracts. Full block suppresses
effects while committing cost/cooldown, emits a zero-damage blocked result
and has no critical-block roll. A nonmelee-casting defender cannot block;
real interruption and the source school lockout remain.
- `abilityCatalog.ts` keeps the saved public `rogue-kick` identity and only
its imported five-second interrupt. The generic merge previously attached
prototype damage and a second four-second interrupt to this exact source
row. Only that known merge changes. Pummel retains its four-second lockout
and level 38 unlock. Tests use level 40 actors and pinned Kam Deepfury at
level 25, with deterministic rolls and synthetic health/cast preparation.
- `combatStore.ts` suppresses main/offhand autos and the owned Scout ranged
scheduler while that actor has an active pacified tag. Target selection
persists; expiry resumes ordinary cadence. Another actor's aura cannot
suppress the player. Accepted-aura scheduler fixtures do not claim a live
Deterrence cast or native readiness promotion.
## Source and remaining limits
Exact client/core evidence: [Lichborne](LICHBORNE_CONTROL_ESCAPE_2026-10-06.md),
[utility extension](UTILITY_HIT_EXTENSION_AUDIT_2026-10-06.md) and
[Deterrence](WOW335_DETERRENCE_SOURCE_2026-10-06.md). Historical inputs were
read only. Pinned `spell_linked_spell` type 2 links Deterrence 19263 to 67801,
even without a client trigger. Its five-second package includes parry, deflect,
pacify, ignore-hit-direction and ranged-hit penalty. Aura 185's private helper
name/comment is corrected; it is not Disarm. The Deterrence helper validates
source signatures only, with no playable import or damage outcome claimed.
Full utility miss/dodge/parry/mechanic-resist tables still need caster hit,
attribute7 and target defense inputs, including ignored combat-result/template
gates. General Magic miss/resist/deflect stays gated. Deterrence needs the
per-hit AlwaysHit source flag and correct post-miss/resist deflect stage;
damage class alone cannot provide this. Exact flee RNG, private stance DUMMY,
Targorr timing, Charm/general control purges, native custom gear and broader
procs remain separate work. Level cap 80, loot and Ready-five scope are intact.
## Verification
The final focused selection passes **138/138 tests in 19 files**. JSON evidence is
`artifacts/control-utility-followup-2026-10-06/focused-vitest.json`. Eleven more
selected existing Kick/Ready/catalog checks pass, with 130 other cases excluded
by the title filter. Ready-five passes seven Vitest and twenty Python checks.
Initial diagnostics catch fixture identity/learnability/facing errors and an
outdated whitelist assertion; corrected fixtures and the final selection pass.
The failed whitelist report is retained separately.
The final selection adds explicit pure and actual learned-cast rejection checks
for Bladestorm under named Fear and the 20511 stun. A purge-capable accepted
grant does not supply permission to cast through those controls. Rejected casts
preserve auras, control, resources, cooldown and GCD. The existing source guard
already enforces this; these additions are test coverage. An intermediate
14-file selection also passes, but omits five intended files and is preserved
as `focused-incomplete-selection.json`; only the final 19-file selection is
credited above.
All three subprocesses use GPT-6 Luna extra-high. Source workers finish, and
the independent integration review finds no further actionable issue after
generic-fear bypass and source-level fixture corrections. The utility worker
verifies the public/source Kick merge and exact contracts. No higher-tier
subprocess is used. Concurrent healer-recovery edits briefly lack an import
during one worker check; the owning concurrent edit supplies it before final
focused validation. Root does not claim ownership of that feature. The first
build catches a narrow/wide control-type mismatch; root changes the comparison
without changing its runtime behavior before rebuilding.
## Final build and content freeze
The normal build's prebuild hooks and 8 GB TypeScript compilation pass. An
earlier concurrent terrain fixture has an invalid material enum until its owner
corrects it; four targeted terrain checks then pass. The default Vite output
fails with Windows EPERM contention in `dist/assets`. A fresh isolated Vite
build succeeds, followed by the normal precompression and release-bundle
verifier. The failed attempts and `build-isolated.log` are retained in the task
artifact directory. No shared output or other process is removed.
The isolated build is frozen under
`artifacts/control-utility-followup-2026-10-06/frozen-20261007-033245765/`.
Its 5,967 files contain 118,418,867 bytes, aggregate SHA-256
`00b7c1b19b0c8e64aba05732c24c7f3f65fa92c5260b4b3dee55391d5af2a2e4`.
The freshly copied content manifest is
`91b22f898ddabb4d20f1331f682852c33e5a6781c75caec9b1e435ebc60a0e39`,
version `content-d1ec6f1f858f21c1`. All 27,587 referenced objects verify before
QA (6,566,442,405 bytes; 21,605 logical files). The prior pass's content is not
reused because the current manifest differs. The build's historical Wailing
bootstrap assets do not select the live test dungeon.
## Final Cellblock Rush evidence
The single final routine run is
`playtest-artifacts/stockade-weapon-utilities/20261007-033835372/` (UTC run ID;
October 6 locally). Normal UI creates a Discipline Priest and four Ready
companions, with isolated pre-entry level 30 preparation. Its seeded boss is
Targorr the Dread, entry 1696, source/live actor `creature-84027`. Native progress
and the results overlay agree on **1/1 in 03:05.6**, Easy/Normal. No player or
party deaths occur; effective player healing totals 2,301.8 HP. Historical
`fullClear` field names certify this entered one-boss slice only.
The committed recorder retains 762 consecutive events, IDs 9–770, with zero
gaps, errors or discarded events/states. Companion Kick events 496 and 765
have `kind: cast`, zero damage and unblocked hit outcomes. No Kick damage event
is recorded. No active source cast is captured for Targorr, so these Kick
results do not prove a live interruption. Shield Bash 536/706 immediately
precedes Daze grants 537/707; Daze duration/movement remains fixture evidence.
Pummel is unobserved: the live actors are below its level 38 unlock. Utility
full blocks, Lichborne/control escape and pacify are deterministic-fixture
coverage, not observed live applications in this seed. There is no Death
Knight in the Ready-only live party.
Existing Disarm evidence contains four tank windows and seven mainhand autos
during them (364, 373, 555, 569, 647, 659, 762). Each records raw damage 57,
versus 68/70 outside those windows. This is consistent with the existing unarmed
fallback and removed weapon contribution, not a requirement to suppress every
swing. Disarm and the new pacify scheduler gate have different source behavior.
Root's labeled `root-evidence-audit.cjs/.json` independently rehashes all 5,967
frozen build files, seven loaded chunks and 2,124 served manifest objects
(77,019,550 bytes). Build and full content manifest remain unchanged; every
checked object matches its address and captured manifest reference, with zero
integrity failures. Raw network response bodies are not retained; the audit
matches immutable local bytes to recorded successful response URLs/status.
Root views the actual roster, equipped-party, route-50 and native results PNGs.
Player/companion bodies, the staff and shield silhouette render. Close-party
overlap and HUD occlusion limit a complete per-companion equipment review.
Nine PNGs exist; no live camera-drag evidence is credited. Page exceptions are
zero; the only console error is favicon 404. The harness cleans up its helper,
server and browser. No gameplay source change or additional live run follows
the frozen build. Final TypeScript compilation also passes after the test-only
rejection additions.
The independent GPT-6 Luna extra-high evidence review finishes without a
discrepancy. It separately checks raw event-ID continuity, native one-boss
completion and agreement between captured fingerprints and root audit. It
confirms the unarmed Disarm evidence and live utility/control attribution above;
it does not rehash the content, run tests/builds/browser, or broaden the audit's
network-body boundary.
Final game release hygiene passes 78 changed paths, including untracked files,
and is recorded in
`artifacts/control-utility-followup-2026-10-06/release-check.log`. Game/vault
changes are reviewed separately, canonical notes are updated, and the task
worklog closes without staging, commit or deployment.
+168
View File
@@ -0,0 +1,168 @@
# Hunter Deterrence catalog selection — 2026-10-07
## Result
The selected Hunter catalog now exposes the exact Spell.dbc player action
Deterrence 19263 as `wow335-hunter-deterrence`, with its source level, cooldown,
resource, GCD, target, item requirement, source attributes, and three parent
aura rows preserved. Its 67801 linked-aura rows remain a separate, explicit
package descriptor; 67801 is not a learned action or a triggered-spell child.
The generated progression file and its generator were not changed. The
catalog-local fallback is inserted only when the generated Hunter chains
contain no Deterrence name or package IDs. An imported candidate is accepted
only if its selected row matches the verified source fields; a same-name
65871 row, an imported linked child, or any candidate drift suppresses the
package rather than substituting a row.
## Why the generated Hunter entry was missing
The read-only source was the local 3.3.5a `patch-enUS.MPQ` at
`../wow335a/Data/enUS/patch-enUS.MPQ`, SHA-256
`c1c06b0d0c34c331b21df7cdd25cc422a650efbd477e42b80849ba30b2e5fc99`.
Its `SkillLineAbility.dbc` contains this row for 19263:
```text
[10865, 51, 19263, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
```
The Hunter source in `scripts/generate-wow335-abilities.mjs` includes skill
line 51 and class mask 4, but `classSpellIds` also requires the row's class-mask
field 4 to contain bit 4. The selected row has class mask zero, so the import
filter drops it even though the Hunter skill-line row is present. A read-only
generation to a temporary output reproduced the omission; no generated files
were written.
## Selected parent row
The same archive's `Spell.dbc` has 239 fields and selects spell 19263 named
Deterrence. The imported field shift is six. The exact catalog values are:
| Field | Selected value |
| --- | --- |
| Source and base level | 60 / 60 |
| Maximum scaling level | 0 |
| Target and range | Self, range index 1, 0–0 |
| Cast time | 0 ms |
| Duration | index 28, 5,000 ms |
| Cooldown | 90,000 ms; category recovery 0 |
| Global cooldown | 0 ms |
| Power | Mana, 0 flat cost, 0 percent cost |
| Prevention type | 0 (`NONE`) |
| Equipped item | class 2, subclass mask 173555, inventory mask 0 |
| Attributes 0–7 | `[327696, 16, 0, 0, 0, 0, 0, 0]` |
| Damage class / school mask | 0 / 1 |
| Icon | `Ability_Whirlwind` |
The exact DBC effect rows are self-targeted `APPLY_AURA` effects with no
triggered spells, period, radius, or mechanic:
| Index | Aura | Parsed amount | Raw base points | DBC coefficient |
| ---: | ---: | ---: | ---: | ---: |
| 0 | 47 | +100 | 99 | 1 |
| 1 | 287 | +100 | 99 | 1 |
| 2 | 25 | 0 | -1 | 0 |
`wow335AbilityCatalog.ts` maps this one verified row through the ordinary
rank path, then uses the source-bound parent aura descriptors from
`wow335DeterrenceRuntime.ts`. That override matters for Aura 47: its source
payload is +100 parry percentage points, so the descriptor uses a flat parry
modifier. The generic Aura 47 mapper uses a percent multiplier and would not
represent this row correctly. The descriptors preserve the existing source
IDs and five-second duration; the 287 effect has no generic deflect tag.
The parent row's selected client tooltip resolves to: “When activated,
increases parry chance by 100% and grants a 100% chance to deflect spells.
While Deterrence is active, you cannot attack. Lasts 5 sec.” The linked server
row `(19263, 67801, 2, 'Deterrence')` and exact 67801 child signature are
documented in [the source audit](WOW335_DETERRENCE_SOURCE_2026-10-06.md).
The same DBC field distinguishes attacks blocked by the pacify prevention
type from silence-only spells. In the 239-field archive, PreventionType is at
raw field 220 (the import shift of six from field 214 in the pinned 234-field
layout). The source enum defines 2 as PACIFY, 1 as SILENCE, and 0 as NONE.
Direct read-only parsing of the pinned archive verified every one of the 189
selected Hunter rank rows plus Deterrence: 32 NONE, 67 SILENCE, and 91 PACIFY.
Five additional IDs appear in generated Hunter spell chains but do not become
selected cast ranks: rank-zero Tame Beast 13481 and Volley damage children
42234, 42243, 42244, and 42245. They are excluded from the runtime lookup
because the ability mapper selects the player cast/channel wrappers.
Arcane Shot (3044), Steady Shot (56641), Aimed Shot (19434), and Wing Clip
(2974) are PACIFY; Explosive Trap (13813) and Mend Pet (136) are SILENCE;
Deterrence (19263) is NONE. The complete spell-ID table is in
`WOW335_HUNTER_PREVENTION_TYPES_BY_SPELL_ID` in
`src/game/wow335AbilityCatalog.ts`. The lookup also checks the selected
Hunter/source identity and accepts the public stable ID used when a generated
source action overlays a core action. Unknown IDs, another class, source, or
name return no prevention value.
The static cast-gate table is deliberately local to the selected catalog. It
was read from `Spell.dbc` with the archive's WDBC record framing and the same
six-field schema shift implemented by
`scripts/generate-wow335-abilities.mjs::parseSpells`; the DBC generator does
not currently retain PreventionType. A second read-only comparison against
all 190 table IDs verified every stored value against raw field 220. The DBC
source pin is WoW build 3.3.5a.12340 and the MPQ SHA-256 recorded above. Field
semantics are pinned to AzerothCore revision
`e822d718322289dd036fb2daf8867ba41283bf9a`: `src/server/shared/SharedDefines.h`
defines `NONE=0`, `SILENCE=1`, and `PACIFY=2`, and
`src/server/game/Spells/Spell.cpp` gates casts using those values. A future
change to the selected archive, DBC field layout, selected Hunter ranks, or
source profile must re-verify the raw table and update this local mapping. It
should move into generated metadata only with explicit profile, class,
source-row, and rank provenance; this change does not broaden the generated
schema.
## Linked package and runtime boundary
`wow335DeterrenceRuntime.ts` owns three parent `apply-aura` descriptors and
two linked 67801 descriptors. The child source effects are Aura 288 (+100,
raw base 99) and Aura 185 (-100, raw base -101), each lasting 5,000 ms. Aura
185 retains its ordinary `incoming-ranged-hit` modifier. Aura 288 has no
generic tag; its ignore-facing meaning is resolved only from the complete
source-bound Deterrence package.
The catalog exposes the selected parent action in Hunter progression at level
60 and keeps the two linked child descriptors separate. Shared cast/runtime
integration applies and removes the full five-aura package atomically. The
runtime validator requires the exact parent ability identity and all five
active aura instances to share source owner, target, applied time, and exact
expiry. It rejects partial, duplicate, expired, foreign-profile, or same-name
65871 packages. See `src/game/wow335DeterrenceRuntime.ts`,
`src/game/wow335DeterrenceRuntime.test.ts`, and the
[Deterrence integration report](DETERRENCE_INTEGRATION_2026-10-07.md).
## Hunter NPC defensive selection
The configured Hunter companion can now select the learned 19263 action from
its own eligible abilities. The early self-defensive branch considers only
engaged mobs currently targeting that companion, and requires the companion to
have no active cast and no active Deterrence package. It triggers below the
configured defensive-health threshold (55% by default) or when a recognized
incoming cooldown mechanic is imminent. The source action must also pass the
normal readiness and target checks, including cooldown, resource, equipment,
and current pacify restrictions. The branch uses the ordinary ability commit
and execution path, preserving its source cost, 90-second cooldown, and zero
GCD. The runtime package applies all five source-linked auras and expires them
together.
This is a Hunter-specific defensive choice based on the companion's own threat
and health/mechanic state; it does not change the general NPC defensive
candidate rules. The player and companion cast gates both consult the exact
selected-row PreventionType lookup: PACIFY (2) spells are blocked while the
actor has an active pacified aura, while SILENCE (1) actions such as Explosive
Trap and Mend Pet remain available. Ordinary melee attacks keep their
existing pacify gate. The focused catalog prevention test covers every
selected Hunter rank and merged public IDs; shared cast/runtime evidence is in
[the Deterrence integration report](DETERRENCE_INTEGRATION_2026-10-07.md).
## Focused verification
`npx vitest run src/game/wow335AbilityCatalog.test.ts -t "selects Hunter Deterrence|retains pinned PreventionType"` passes both selected catalog tests.
The Deterrence case checks the stable selected ID, level 60 unlock, 90-second
cooldown, zero cost/GCD, exact source attributes and weapon requirement, all
three parent aura rows, both linked child rows, and rejection of 65871/67801
as independent Hunter actions. The prevention case checks all 190 selected
rank IDs against the source map, class/source/name/rank rejection, and public
merged IDs for Arcane Shot and Steady Shot. Source-contract tests separately
cover profile, parent/child, and link drift.
+155
View File
@@ -0,0 +1,155 @@
# Hunter Deterrence integration — 2026-10-07
Hunter Deterrence 19263 is available at level 60 to players and configured
Hunter companions. It grants its three parent auras and the two linked 67801
auras to the same caster for five seconds, costs no Mana, preserves the existing
global cooldown and starts its sourced 90-second cooldown. The selected source
requires a matching equipped weapon. The existing Training Gear staff satisfies
that mask; a source Disarm does not remove the matching item, and the pinned
nonpassive aura-spell exception still permits this cast.
## Source and ownership
The pinned Spell.dbc SHA-256 is
`57011d528fd66cf39f5ab6fb168e389ab9e4cc1b8050f7201a54239d489b415c`;
AzerothCore is `e822d718322289dd036fb2daf8867ba41283bf9a`. The exact type-2
`spell_linked_spell` row binds 19263 to 67801. Same-name 65871 and child 67801
remain unavailable as independent Hunter actions. The older
[source audit](WOW335_DETERRENCE_SOURCE_2026-10-06.md) records the raw package.
- `scripts/dungeon-pipeline/export-enemy-damage-types.mjs` owns generated raw
Attributes0/3/7 (DBC fields 4/7/11). `mobDamageTypes.ts` and
`enemyAttacks.ts` retain them on normalized, source-identified WoW attacks.
All 671 existing WoW source rows and RuneWaker mappings are retained. Unknown,
native and omitted non-damage rows do not acquire invented zero attributes.
- `wow335AbilityCatalog.ts` supplies a narrow fallback for selected 19263,
which the generator's class-mask filter omitted despite its Hunter skill-line
row. Its pinned PreventionType lookup covers all 190 selected Hunter rank IDs
and the public merged ability aliases.
- `wow335DeterrenceRuntime.ts` validates the selected ability and all five real
aura instances: exact behavior, owner, target, application time and lifetime.
- `combatStore.ts` applies the linked children after accepted parent effects,
forces this self cast to the caster even when a caller supplies a foreign
target, synchronizes malformed/expired packages and resolves incoming results.
- `partyRuntime.ts` selects a learned, ready self defense while a live enemy
targets the Hunter and health is below its configured defensive threshold
(default 55%), or a recognized defensive mechanic is imminent. It rejects an
active cast and respects equipment, cooldown, resources and existing GCD.
## Defense and attack behavior
The parent supplies +100 parry percentage points, sourced spell deflection and
pacify. Linked 67801 supplies ignore-facing and -100 incoming ranged-hit
percentage points. Simultaneous Hunters keep separate owner-local packages.
Incomplete, foreign and expired packages cannot lend parry or ranged-hit stats
to incoming resolution; the shared tick removes their package members.
Eligible landed, direct WoW Magic/ranged spell packets become an explicit
`deflect` outcome with zero effective damage. Raw damage remains diagnostic;
critical/block/resistance mitigation is discarded, no absorb is consumed and
no landed-hit proc is credited. Earlier miss/full resist remains the actual
outcome. Ordinary ranged autos use Aura185's miss modifier, and melee uses
parry. Known source flags are matched against the complete source row tuple
before applying AlwaysHit, NoActiveDefense, NoAttackMiss or defense exclusions.
The complete package rejects the front-arc requirement through its linked aura.
The exact 100% deflect package also suppresses eligible hostile control, aura,
periodic application, pull and leech-healing riders. Damage retains its real
roll. Stun is read from the original combat-update snapshot, before a newly
queued slow changes control state. Source bypasses, stunned defenders, periodic
ticks, autos and unknown/native source records do not borrow spell deflection.
Pacify stops owner weapon autos and selected Hunter PACIFY=2 attacks, including
Arcane Shot and Steady Shot. SILENCE=1 actions such as traps and Mend Pet remain
eligible under their ordinary prerequisites. This does not pacify the pet.
## Verification
The final focused run passes **110/110 checks in 15 files**, including 12
actual cast/defense integration cases. The exporter Node test and two selected
catalog/prevention checks pass. Ready-five passes seven Vitest and twenty Python
checks. Final 8 GB TypeScript, normal prebuild hooks, isolated Vite output,
precompression and release-bundle verification pass; the isolated output avoids
the previously observed shared `dist` lock. Build logs and JSON reports are in
`artifacts/deterrence-continuation-2026-10-07/`. Actual player/NPC fixtures are
`wow335DeterrenceCast.integration.test.ts` and
`wow335DeterrenceDefense.integration.test.ts`.
The required avatar scope also passes **56 checks in 11 files**, following the
equipped-item requirement change. No character/gear rendering code changed.
The fixtures prove actual player and NPC Frostbolt deflection, no newly applied
slow on a deflected spell, existing stun exclusion, melee parry, periodic and
AlwaysHit exclusions, source-bound cast requirements, linked expiry and
simultaneous owners. Source ranged spell 2643 truthfully misses under Aura185;
the helper separately verifies its eligible deflect branch for a landed input.
Arcane/Steady casts reject while Freezing Trap succeeds under pacify. A torn
Aura185 package matches the same-seed auto baseline; regular tick cleanup leaves
the second Hunter's valid package intact. Native/unknown source rejection is
helper evidence, not a new native live encounter.
The final frozen build contains 5,967 files / 118,501,108 bytes; aggregate SHA-256
`a30787cafc7e1421e872cb37f883147177981b6627dc4238bf89f46ffb850ec2`.
Fresh content `content-151109efcb20cc00` has manifest SHA-256
`40d5c9e16d8045b8c240d57ca52017aaf95e423c44f96507aceb02285dca693c`;
all 27,587 referenced objects / 6,554,643,247 bytes verify against that captured
manifest before entry. The isolated snapshot is
`artifacts/deterrence-continuation-2026-10-07/frozen-20261007-161003375/`.
One ordinary Cellblock Rush run, `20261007-161404213`, selects **Hamhock 1717**
(`creature-79098`) and clears native **1/1 in 03:13.6**, with no deaths. The
isolated UI-created Discipline Priest enters at level 30 with four asserted
Ready companions; normal progression finishes the Priest at 32 and companions
at 31. Six attributed Lesser Heal events supply **1,952 effective healing**,
zero overheal. No live combat-state seeding or Boss Testing is used.
Root independently verifies the unchanged frozen build/manifest, all seven
loaded chunks and 2,124 served manifest objects / 77,019,550 bytes with zero
integrity failures. Event coverage is **745 consecutive IDs 9–753**, with no
gaps, discarded events or recorder errors. There are zero page exceptions;
the only console error is the existing favicon 404. The audit matches immutable
local bytes to captured successful response URLs/status and manifest references;
raw response bodies are not retained or independently hashed.
Root inspects the actual roster, equipped entrance, route-50 and results PNGs
under `playtest-artifacts/stockade-weapon-utilities/20261007-161404213/campaign/`.
Bodies and visible equipment render; entrance overlap and partly offscreen
companions limit certification of every gear/race silhouette. The file named
`bite-sized-stormwind-stockade-boss-arrival.png` shows the native results overlay.
No camera-drag proof or level-60 live Deterrence claim is credited. This is the
one selected boss slice, despite the results screen's generic full-clear label.
The harness cleans up its browser/helper/server. No gameplay change or second
live run follows the freeze.
The independent Luna extra-high evidence review confirms those fingerprints,
event coverage and native result without launching another run or rehashing
content. Native completion ends traversal at checkpoint 75/86 before the
dedicated boss handler (`bossClearAttempted:false`); observed boss death and
persisted kill progress prove the clear. Do not claim a completed scripted boss
handler or every route checkpoint. Its report is
`artifacts/deterrence-continuation-2026-10-07/luna-evidence-review.md`.
Final release hygiene passes all 101 changed paths, including untracked files;
the user Git index remains empty.
## Remaining boundaries
The underlying miss/resist/armor formulas remain the existing simulator model,
not a complete AzerothCore hit table or RNG reproduction. The exported enemy
table excludes unsupported/non-damage rows, so general shout/utility deflection
remains unproven. Ordinary miss/resist control riders without this exact
Deterrence package retain their earlier behavior. Same-update controls use the
original-frame simultaneous policy; source server event ordering is not claimed.
The always-equipped Training Gear fixture does not exercise a truly empty
matching-equipment branch. Unknown/custom/native rates and equipment remain
separate source gaps.
The routine level-30 Ready-only live party does not unlock level-60 Deterrence;
its player/NPC behavior is actual store-fixture evidence. Cellblock Rush proves
only the selected one-boss route and regression behavior. Level cap 80, saved
stat/profile compatibility, loot wiring and readiness policy remain intact.
No full suite, expanded balance sweep, staging, commit or deployment is part of
this continuation. All subprocesses use GPT-6 Luna extra-high.
Related: [catalog](DETERRENCE_CATALOG_2026-10-07.md),
[runtime contract](DETERRENCE_RUNTIME_CONTRACT_2026-10-07.md),
[hit source inputs](ENEMY_HIT_SOURCE_INPUTS_2026-10-07.md).
@@ -0,0 +1,87 @@
# WoW 3.3.5 Hunter Deterrence runtime contract — 2026-10-07
## Scope
`src/game/wow335DeterrenceRuntime.ts` binds the selected Hunter catalog row to
the audited Spell.dbc 19263 parent and its `spell_linked_spell` Aura link to
67801. It supplies source-shaped aura descriptors and a narrow post-hit
deflect gate. The shared combat store, party runtime, and combat-result paths
own cast execution, actual aura application/removal, and outcome recording.
The five source aura definitions are identified by their source spell/effect
IDs: parent 19263 Auras 47, 287, and 25; linked child 67801 Auras 288 and 185.
All five instances must belong to the same Hunter self-cast, target that Hunter,
share one application time, and expire exactly five seconds later. The runtime
contract returns no Deterrence package when any member is missing, duplicated,
expired, foreign-owned, or out of step with the other members. Removing or
expiring one member should remove the other members for that same owner,
target, and application time.
The helper exports the parent effects for the selected catalog mapping and the
linked-child effects for the original cast target. Aura 47 carries a flat +100
parry modifier. Aura 25 carries the pacify tag. Aura 287 supplies the 100-point
spell-deflect source aura. Aura 288 removes the attacker's frontal-arc
requirement for this package. Aura 185 carries the -100 incoming ranged-hit
modifier; the existing shared hit-stat path consumes it, so the combat caller
must not add a second copy of that penalty.
## Deflect gate
`resolveWow335DeterrenceIncoming` is a final gate after the existing combat
resolver has produced a landed `hit`, `crit`, or `block`. It preserves `miss`,
`resist`, `dodge`, and `parry`. For an otherwise eligible event it returns the
distinct `deflect` outcome; the source aura is 100%, so this gate adds no random
roll.
The input must identify a non-periodic WoW 3.3.5 spell source and match the
exact enemy damage-source row, including DamageClass, SchoolMask, and raw
AttributesEx0/3/7. Only Magic (DamageClass 1) and ranged (DamageClass 3) spells
qualify. DamageClass None, melee, unknown, foreign-profile, periodic, and
weapon-auto inputs remain unchanged. A stun suppresses deflection. The core's
source bypasses are preserved: AttributesEx3 `ALWAYS_HIT` (`0x00040000`)
suppresses both branches; ranged DamageClass also skips the deflect check for
AttributesEx0 `NO_ACTIVE_DEFENSE` (`0x00200000`); Magic DamageClass skips it for
AttributesEx7 `NO_ATTACK_MISS` (`0x02000000`). The front-arc gate applies unless
Aura 288 is active. A complete accepted Deterrence package always contains Aura
288, so an attacker behind the Hunter remains eligible.
Ordinary ranged autos never produce `deflect`. They receive Aura 185's separate
incoming ranged-hit modifier through the existing aura-stat path. The helper
does not calculate general miss/resist chances, and it does not widen the
simulator's existing combat table to other spells or profiles.
The shared combat path also uses this exact eligibility gate before applying
non-damage spell riders while the complete Deterrence package is active. For a
source event that is guaranteed to deflect if it lands, control, target-aura,
periodic, pull, and leech-healing riders are skipped while damage still goes
through the ordinary hit resolver and records `deflect` only after its normal
landed result. This suppression is package-specific; ordinary sourced attacks
outside Deterrence retain the simulator's existing rider behavior on miss or
resist. Same-update incoming events use the combat store's original-frame stun
snapshot, consistent with its simultaneous batch policy.
## Identity and provenance
The source contract continues to use the exact audited 19263, 67801, and
type-2 link signatures in `src/game/wow335Deterrence.ts`. The runtime ability
contract accepts only the selected `wow335-hunter-deterrence` Hunter mapping,
its `wow335-progression` source, DBC ID 19263, self target, and the three exact
parent source effects. Runtime activation is derived from the actual serializable
`ActiveAura` records; callers do not pass a copied source-package object as
proof. Incoming deflection independently checks its spell ID and hit attributes
against the exact WoW damage-source table. Missing or mismatched source fields
fail closed.
The pinned source evidence and the limits of the imported behavior are recorded
in [`WOW335_DETERRENCE_SOURCE_2026-10-06.md`](WOW335_DETERRENCE_SOURCE_2026-10-06.md).
The source row authenticates hit-class and bypass metadata; the game's current
miss/resist calculations remain its own policy. This contract does not create a
complete AzerothCore hit table.
## Focused verification
Run `npx vitest run src/game/wow335Deterrence.test.ts src/game/wow335DeterrenceRuntime.test.ts`
for the exact source rows, linked package identity and lifetime, cleanup scope,
branch-specific bypass bits, and unsupported-input exclusions. The mechanics
work remains within the project's Ready-five certification boundary, level-80
cap, and existing loot scope.
@@ -0,0 +1,99 @@
# Disarm weapon contribution audit — 2026-10-05
This pass adds reusable character-side projections for item-dependent auras,
spell-selected weapon channels, and temporary weapon damage under the
source-backed Ascension/Epoch Disarm tags. The helpers are in
`src/game/enemyDisarmRuntime.ts`; the checks are in
`src/game/enemyDisarmRuntime.test.ts`.
## Core behavior verified
In the read-only historical AzerothCore tree, `SpellAuraEffects.cpp` maps Aura
67/254/278 to main-hand/off-hand/ranged flags. Applying Disarm recalculates the
player's item-dependent auras and weapon damage while retaining equipped item
stats. Removing Disarm clears the flag and recalculates the affected channel's
weapon auras. Creature spells use `Spell::CheckItems` to reject damage-class
melee/ranged spells whose selected attack type is unavailable.
`Player::HasItemFitToSpellRequirements` searches other usable equipped items
for a class/subclass/inventory-mask match. Passive item-requirement auras are
removed when Disarm leaves no matching usable weapon. The core keeps an active
nonpassive aura spell through the specific aura-cast exception. Separately,
`UpdateWeaponDependentAuras` recalculates weapon-aura contributions per attack
type, and `CheckAttackFitToAuraRequirement` tests the item in that channel.
`Spell` selects main-hand for a melee damage-class spell by default and
off-hand when AttributesEx3 `0x01000000` is set. A ranged damage-class spell
uses ranged when the core classifies it as a ranged-weapon spell; that decision
uses AttributesEx `USES_RANGED_SLOT` (`0x00000002`), the ranged weapon subclass
mask, or a Hunter-family exception. Other ranged damage-class spells use the
main-hand attack type. The player item check does not impose a blanket gate on
all physical damage-class casts.
The source was read from:
- `../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/game/Spells/Auras/SpellAuraEffects.cpp`
- `../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/game/Entities/Player/Player.cpp`
- `../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/game/Spells/Spell.cpp`
- `../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/game/Spells/SpellInfo.cpp`
- `../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/shared/SharedDefines.h`
- `../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/game/Entities/Item/ItemTemplate.h`
## Helper contracts
`enemyDisarmItemDependentAuraSuppressionIds` returns source-caster-owned
passive aura instance IDs whose matching equipped weapon slots are all
disabled. It preserves nonpassive aura spells and the stored aura state, so a
caller can build an effective combat aura view that restores the passive
contribution automatically when Disarm expires.
`enemyDisarmAurasForWeaponChannel` creates the attack-type-specific aura view.
It keeps an item-requirement aura contribution only when the selected usable
weapon matches the aura requirement, and suppresses it while that channel is
disarmed. This allows an enabled matching off-hand contribution to remain
available while the main-hand calculation uses the unarmed profile.
`enemyDisarmAbilityWeaponChannel` mirrors the source spell attack-type choice.
`enemyDisarmAdjustedAbilityWeapon` returns the 1–2 damage, 2-second unarmed
main-hand profile, no weapon for disabled off-hand/ranged channels, or the
unchanged weapon for other channels. Feral main-hand weapon stats remain
unchanged. `enemyDisarmBlocksNpcWeaponAbility` exposes the NPC-only selected
damage-class channel gate separately from player ability requirement checks.
## Integration boundary and limits
The party runtime uses `effectiveActorAuras` for global passive suppression and
channel-specific weapon-aura views. Party ability casts retain the player-style
equipped-item requirement gate, and generic amount calculations receive the
member's active Disarm channel set so source-selected weapon contribution can
be adjusted without rejecting unrelated physical casts. Party main-hand autos
use the source 1–2 / 2-second WoW punch; the dual-wield integration case confirms
an enabled off-hand still contributes. The party auto path also asks the native
Runewaker helper for a verified unarmed main-hand profile and cadence, while
ranged autos retain their existing channel behavior. Periodic party effects
are applied through `CombatStore.applyTimedActorEffect`; its native snapshot
path checks the source actor's active main-hand channel before passing the
verified profile into the native periodic calculator.
Generated party characters use the player's class item-requirement rules. The
hostile creature `Spell::CheckItems` channel gate remains available as a
separate helper and is not imposed on party class builds. The centralized
combat store owns the player and party passive-aura projection and generic
ability weapon contribution. The simulator still cannot infer item durability
or equipment eligibility missing from its resolved loadout.
Native Runewaker unarmed main-hand damage is implemented only when the active
five training profile is source-verifiable. Its sidecar does not model
`Main_DMG_Per`, `DMG_AllWeapon`, `DMG_Unarmed`, `AtkSpeed`, `Main_ATKSpeed_Per`,
`AttackSpeed_AllWeapon`, or `AttackSpeed_Unarmed`; those rate channels remain an
explicit neutral-rate boundary. Unsupported profiles keep their existing
fallback behavior rather than borrowing the WoW punch profile.
## Focused validation
`npx vitest run src/game/enemyWeaponDebuffs.test.ts
src/game/enemyDisarmRuntime.test.ts
src/game/enemyDisarmRuntime.integration.test.ts
src/game/romNativeDisarm.test.ts` passes: 4 files, 21 tests. The party integration
tests cover player and companion cast handling, an enabled party off-hand, native
main-hand damage/cadence, and the existing ranged Scout channel behavior.
+8
View File
@@ -3,6 +3,14 @@
Use this runbook for requests to inspect or fix the current dungeon reports.
It is intentionally repo-relative except for the production endpoint.
Routine mechanic/browser QA defaults to **Stormwind Stockade: Cellblock Rush**
(`bite-sized-stormwind-stockade`). Each run selects one Stockade boss from its
shared run ID, so record the boss actually observed. Isolated Boss Testing has
its separate Hamhock default; full-source Stockade campaigns require explicit
selection. See `docs/TEST_DUNGEON_POLICY.md` and `AGENTS.md`. A report tied to a
specific dungeon still requires inspecting that source and the user's authorized
reproduction; existing Wailing reports do not make it the default test dungeon.
## 1. Read the live queue first
The public read endpoint is:
+132
View File
@@ -0,0 +1,132 @@
# Automatic enemy offhands — 2026-10-05
Current source-table recovery supersedes the missing equipment-map limitation
recorded below. See [the 2026-10-06 equipment mapping audit](ENEMY_EQUIPMENT_MAPPING_2026-10-06.md)
for the pinned SQL, Item.dbc validation, importer output, and runtime helper.
## Result
Added narrow helpers for the two historical AzerothCore automatic offhand
gates: the creature-template `USE_OFFHAND_ATTACK` flag and the default `AUTO`
mode's resolved offhand weapon check. The flag helper binds only the five
matching creatures present in HealerMan's imported template-reference subset.
The item helper requires a nonzero item ID and an already resolved Item.dbc
class of `WEAPON` (2). It does not map an `equipment_id` to an item because
that table is absent from the pinned world import.
The helpers are in [enemyAutomaticOffhand.ts](../src/game/enemyAutomaticOffhand.ts).
They do not schedule attacks or mutate combat state. Runtime should treat
`enemyFlagDrivenOffhandContract(entry)` as an intrinsic creature capability and
feed it into the existing ordinary WoW offhand path. Keep this source flag
separate from the simulator's temporary spell-granted capability: core sets the
flag mode in creature initialization and entry updates, so evade, death, and
encounter reset must not clear it while the creature entry remains the same.
The simulator's existing reset policy can continue to clear spell-granted
Dual Wield state.
`enemyAutoEquippedOffhandContract({ entry, name?, offhandItemId,
offhandItemClass })` resolves the default `AUTO` item gate only after a caller
has loaded the actual offhand virtual item and looked up its class. An absent,
zero, unresolved, or non-weapon item returns no contract. Do not use a model,
creature appearance, or `equipment_id` alone as a substitute for the missing
slot-to-item mapping. Keep both helpers on the source WoW creature path; the
existing RuneWaker, summon, and character-defender exclusions remain in force.
## World source and coverage
The imported AzerothCore world source is commit
`4d9d1d4b5723e819c5c390f6ca1177283dbfb8e3`. Its lock pins `creature.sql` at
SHA-256 `f54ddfe7ee00080b4b0bc970a809d6f947f6fb2627dbcd67e92b402fb34cb701`
and `creature_template.sql` at SHA-256
`0066e4fd35b809986dd325487515087f5a95f4ffe50ea03846c8d8bf5196870a`.
`creature_template.sql` has 29,947 rows, 43 of which set
`flags_extra & 0x00000800`. The imported runtime reference contains 1,671
creature templates; five carry that bit:
| Entry | Creature | `flags_extra` |
| ---: | --- | ---: |
| 4540 | Scarlet Monk | 2048 |
| 10478 | Splintered Skeleton | 2048 |
| 10488 | Risen Construct | 2048 |
| 16593 | Shattered Hand Brawler | 134219776 |
| 16808 | Warchief Kargath Bladefist | 2048 |
The source lock includes `creature.sql` rows with an `equipment_id` field, but
does not include `creature_equip_template.sql`. The pinned spawn table has
149,879 rows; 51,248 have a nonzero `equipment_id` value (the distinct values
are `-1`, `1`, and `2`). Those values select equipment-set IDs; they do not
identify an offhand item by themselves.
I found `creature_equip_template.sql` in two local AzerothCore backup trees:
`../wow-pvt-server-backups-2/azerothcore-wotlk/data/sql/base/db_world/creature_equip_template.sql`
and
`../WoW-Pvt-Server-Backups/azerothcore-wotlk/data/sql/base/db_world/creature_equip_template.sql`.
The copies are byte-identical at SHA-256
`D95423028E4D9CD7068E317BDE66ED847DC8238F4A6AA952D9EA40EF36109A1A`, and their
rows include Stockade mappings such as `1696/1 -> 5305, 5305`,
`1711/1 -> 2184, 2184`, and `1716/1 -> 2179, 1897`. These are useful leads,
but they are not bound to this import: the adjacent archived
`creature_template.sql` and `creature.sql` hashes are respectively
`e20e921613a02f8a86e997fd0d1d959dbe868bd6886151c8ca5f6c187a549356` and
`135c78413da1bbbce0c65ee4ee833c0f19343933b3a0e30f82ff023f37aa6164`, which
do not match the pinned inputs. The equipment-table path is also absent from
the pinned Git tree. The importer therefore does not bind those mappings.
The local WotLK client
`../wow335a/Data/patch-A.MPQ/DBFilesClient/Item.dbc` and AzerothCore server
`../wow-pvt-server-backups-2/azerothcore-wotlk/data/Item.dbc` have the same
SHA-256:
`22061a811523790ddd2ee95b36ade2ac6e0c79a8b3121324d32a639acf50567f`.
`ItemEntry::ClassID` is field 1 in the core DBC structure and the client DBC
uses the matching `Class` field. Item class 2 is `ITEM_CLASS_WEAPON`. The core
`Creature::HasWeapon(OFF_ATTACK)` checks only that the offhand virtual item
resolves and its class is weapon; it does not check subclass or inventory type.
This pins the gate logic and the local DBC bytes, but does not supply the
missing equipment-set-to-item mapping for the locked world rows.
## Core behavior reference
The behavior audit uses the local read-only AzerothCore checkout at HEAD
`e822d718322289dd036fb2daf8867ba41283bf9a`. This is a core-behavior reference,
not the world-data commit above.
- `CreatureData.h:57` defines `CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK = 0x800`.
- `Creature::InitEntry` and `Creature::UpdateEntry` set
`DualWieldMode::ENABLED` when the flag is present (`Creature.cpp:565-566,
614-615`).
- `Creature::HasWeapon(OFF_ATTACK)` returns true in `ENABLED` mode. In `AUTO`
mode it resolves virtual item slot 1 and accepts only a valid item whose
`ClassID == ITEM_CLASS_WEAPON` (`Creature.cpp:3299-3317`). The core enum is
in `Unit.h:587-590`; `ITEM_CLASS_WEAPON` is 2 at `ItemTemplate.h:293`.
- `Creature::SelectLevel` initializes both base and offhand from the same
generated creature range (`Creature.cpp:1540-1549`).
`Creature::CalculateMinMaxDamage` uses the same range, template variance,
attack-power contribution, and damage modifier for either hand
(`StatSystem.cpp:1119-1167`). `UNIT_MOD_DAMAGE_OFFHAND` applies the default
0.5 total damage factor (`Unit.cpp:401`).
- Both swing timers use `CreatureTemplate.BaseAttackTime`
(`Creature.cpp:617-618`). Ordinary white swings add 19 percentage points to
miss chance when an offhand is available (`Unit.cpp:15288-15290`). The
existing Dual Wield source contract supplies the half-swing initial offset
and 200 ms simultaneous-swing presentation stagger.
Relevant paths in the reference checkout are `src/server/game/Entities/Creature/CreatureData.h`,
`src/server/game/Entities/Creature/Creature.cpp`,
`src/server/game/Entities/Unit/StatSystem.cpp`,
`src/server/game/Entities/Unit/Unit.cpp`,
`src/server/game/Entities/Unit/Unit.h`,
`src/server/game/Entities/Item/ItemTemplate.h`, and
`src/server/shared/DataStores/DBCStructure.h`.
## Validation and limits
`npm test -- --run src/game/enemyAutomaticOffhand.test.ts` passes four focused
tests. npm's `pretest` hook also ran the existing loot-catalog generator; it
reported the existing 9-boss/23-item catalog, with no loot-file change.
The flag path is implemented from the locked creature-template data. The AUTO
path is implemented as a strict, reusable item-class gate, but no locked world
equipment mapping currently supplies it with item IDs. Exact automatic
offhand availability for the imported `equipment_id` and template-default
cases remains unresolved until a matching equipment-template source is pinned
or imported.
+90
View File
@@ -0,0 +1,90 @@
# Enemy Bloodlust source contract — 2026-10-05
`src/game/enemyBloodlust.ts` records the sourced NPC contract for spell 6742
and exposes the melee swing-interval calculation used when independent
Aura 138 haste effects overlap. It models one explicitly selected friendly
creature per application. It does not infer Shaman player-party semantics from
the similarly named player spell.
## Pinned client rows
The active Ascension Spell.dbc is
`../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc`
(SHA-256
`2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce`). The
Epoch Spell.dbc is
`../HealerMan-Storage/pipeline-work/dungeons/epoch-client/DBFilesClient/Spell.dbc`
(SHA-256
`d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3`). Both
contain the same spell 6742 fields:
| Spell.dbc field | Value |
| --- | ---: |
| Range index | 4 |
| School mask / damage class | 8 / 1 |
| Duration index / resolved duration | 9 / 30,000 ms |
| Dispel / stack amount | 1 (Magic) / 0 |
| Attributes 0–7 | 0 |
| Effect | 6 (`APPLY_AURA`) |
| Aura / base points | 138 (`MOD_MELEE_HASTE`) / +30 |
| Implicit targets A / B | 21 (`TARGET_UNIT_TARGET_ALLY`) / 0 |
| Radius / misc value / period | 0 / 0 / 0 |
| Trigger spell | 0 |
The duration comes from the pinned shared patch-S SpellDuration.dbc
(`eeae44ef0185924f3d6ec57ab2701c66566db86e51ab0bae017a9449126eb3a0`); the
shared SpellRadius.dbc fallback is
`dba6ed2f165f75c84dda5f32ae46b1a01fe562efd88fa51fd19365705c3e6a44`. SpellRange
index 4 comes from shared patch-S SpellRange.dbc (SHA-256
`bb899631818942a7a7100abfb7a970612a79ac99637b1b459561e2b108125ddd`): both
friendly and hostile ranges are 0–30 yards, with flags 0. This row and the
effect target describe a selected friendly unit, not an area target; the
effect has no radius.
## Historical NPC selection and cast gates
The read-only AzerothCore world snapshot's `creature_template_spell.sql` lists
Hamhock (entry 1717) with spells 6742 and 421. Its `smart_scripts.sql` rows
provide two separate Bloodlust paths:
- Update-in-combat event 0 has a fixed 5,000 ms initial delay, no repeat timer,
100% chance, and NOT_REPEATABLE flag 1. It casts spell 6742 with cast flags
32 (`SMARTCAST_AURA_NOT_PRESENT`) on target type 1 (self). AzerothCore only
processes this event while Hamhock is engaged; the cast flag skips recasting
while that target already has Bloodlust.
- Friendly-missing-buff event 16 uses spell 6742, radius 30, repeat interval
10,000 ms, and `onlyInCombat=0`. It casts spell 6742 with flags 0 on target
type 7 (`SMART_TARGET_ACTION_INVOKER`), the selected missing-buff recipient.
The event starts active without an initial delay and resets its 10-second
repeat timer after it processes a recipient.
The historical `FriendlyMissingBuffInRange` predicate further requires the
candidate creature to be alive, in combat, non-hostile to the caster, within
30 yards on the same map and phase, and missing spell 6742. The search uses a
creature-list searcher, so this AI path selects creatures rather than the
player party. Its predicate has no self-exclusion or line-of-sight check;
the normal, untriggered cast still uses ordinary spell validation. Distance
checks include the source and target object sizes. These are source gates; the
current game entity state has no faction, phase, or collision-radius data and
must document its corresponding selection approximation.
## Haste stacking
AzerothCore maps Aura 138 to `HandleModMeleeSpeedPct`, which applies a separate
percentage attack-speed factor to main-hand and off-hand swing intervals. The
same-effect spell-group lookup suppresses weaker members only when the data
places them in an exclusive group. The historical `spell_group.sql` does not
place either 6742 or Enrage 8599 in its “Melee Haste Buffs” group. Their two
+30% effects therefore combine as separate factors: an active Bloodlust and
Enrage yield `1 / (1.3 × 1.3)`, or about 0.591716 of the prior swing interval.
They do not become one additive +60% modifier (0.625 interval factor).
`enemyMeleeHasteIntervalMultiplier` applies the sourced positive and negative
Aura 138 interval factors to marked source modifiers in the already-filtered
active aura list for one enemy, then preserves the existing additive interval
calculation for unmarked haste modifiers. It leaves auto-attack ability
cooldowns and unrelated haste channels unchanged. The Bloodlust contract
itself exposes only melee haste, Magic dispel, a 30-second duration, and the
explicit-friendly 30-yard target shape.
Focused validation is `npx vitest run src/game/enemyBloodlust.test.ts src/game/enemyBloodlust.integration.test.ts`.
@@ -0,0 +1,58 @@
# Enemy control hit and immunity follow-up — 2026-10-06
## Finding
There is no complete, source-bounded generic hit helper to add for shout control. The pinned rows do establish ordinary miss, resist, and deflect gates for the rows whose `DamageClass` is Magic, but AzerothCore computes those outcomes from the live caster, defender, full `Spell`, world miss-rate policy, and random roll. The None-class children take a different branch and do not receive those Magic hit rolls. A fixed miss percentage or a helper that accepts only a spell ID and `CharacterDefender` would not match the source.
Historical behavior below is pinned to read-only AzerothCore `e822d718322289dd036fb2daf8867ba41283bf9a`. The active HealerMan runtime and generated data remain authoritative for implementation. The earlier [shout speed and immunity audit](ENEMY_SHOUT_SPEED_IMMUNITY_2026-10-06.md) records the client-profile hashes and full eight-word attribute tuples for these four spells.
## Pinned shout hit branches
All four spells have `SchoolMask=1` (Normal/physical) and spell-level `Mechanic=5` (Fear). The spell damage classes differ by row and profile:
| Spell | Ascension | Epoch | Core hit branch |
| --- | --- | --- | --- |
| 5246 parent | Magic | Magic | `MagicSpellHitResult` in both profiles |
| 19134 parent | Magic | Magic | `MagicSpellHitResult` in both profiles |
| 20511 child | Magic | None | Magic roll in Ascension; aura-only None handling in Epoch |
| 29544 child | None | None | Aura-only None handling in both profiles |
The `Unit::SpellHitResult(Unit*, Spell const*, bool)` overload first checks whole-spell and effect immunities, then dispatches by `DamageClass` (`Unit.cpp:3706–3790`). A Magic-class shout therefore reaches `MagicSpellHitResult` despite its physical school. That routine (`Unit.cpp:3503–3634`) calculates miss from relative caster/defender levels, configured miss multipliers, caster spell modifiers and hit bonuses, defender hit-taken and area-avoidance bonuses, and player hit-taken rating. It then adds mechanic and eligible debuff resistance. The extra binary-school resistance term does not apply to these Normal-school rows. Deflect is possible when the target is in the caster's front arc (or ignores hit direction), is not stunned, and has a deflect aura. The routines also depend on actor types and state such as vehicles, trigger creatures, and dead non-player targets.
These are source-representable gates only when the runtime can provide the relevant actors and spell context. The core call receives the original caster as `this`, the actual `Unit*` victim, and the active `Spell*`; `Spell::AddUnitTarget` calls it with `m_originalCaster` (`Spell.cpp:2293–2367`). A faithful integration needs the caster's target-relative level, hit and spell-modifier data, relevant owner/totem/vehicle state, and the defender's level, active immunities, mechanic/debuff resistance, hit-taken and area-avoidance data, facing, stun state, deflect/reflect auras, and evade/death state. It also needs the source row and the configured miss-rate policy. The current shout contract does not carry that information, and area recipients can include actor types outside player/party `CharacterDefender` snapshots.
For a None-class row, the source first performs its immunity checks, then returns a successful hit for a nonzero spell family or for aura-only effects (`Unit.cpp:3761–3790`). Child 20511 and 29544 are aura-only in both pins, so their None-class profiles have no ordinary Magic miss, resist, or deflect roll. Preserve this difference: a generic roll on every triggered child would add an unsupported Epoch 20511 and 29544 outcome.
The triggered child remains tied to the parent's explicit victim. The core records the parent's hit result per target, and runs target effects only for a successful hit (`Spell.cpp:2583–2637`); effect 0's trigger therefore runs only for the successful explicit-victim target. The current runtime validates that explicit victim's eligibility, range, and line of sight before selecting the child, then applies it directly in [combatStore.ts](../src/game/combatStore.ts) around the `triggered-shout` branch. Root integration should preserve that victim binding and place any supported parent hit gate before child execution.
## Whole-spell control immunity and active-aura purge
The shout rows set spell-level Fear, so the core checks Fear mechanic immunity against the whole spell before per-effect immunity (`Unit.cpp:10032–10120`). This rejects the parent and its riders as a whole. Child 20511 remains a Fear-mechanic spell even though its first aura is stun: fear immunity rejects the whole child; stun-state immunity is narrower and may strip the stun effect while leaving Ascension's separate physical-damage-taken rider. Epoch 20511 has no separate rider. These distinctions match the existing shout audit.
The local generated WoW 3.3.5a ability JSON was parsed and filtered by spell ID. Its imported Warrior rows identify Berserker Rage 18499 and Bladestorm 46924 as immunity candidates. The generator now preserves raw `attributes1` and `attributes5` alongside the selected spell-defense metadata, and apply-aura effects retain raw base-points, die-sides, and points-per-level scalars. I read the corresponding raw Spell.dbc fields from the local `patch-enUS.MPQ` to establish the purge bit rather than inferring it from tooltips:
| Imported spell | Relevant generated effect | Raw `Attributes1` | Source result |
| --- | --- | ---: | --- |
| 18499 Berserker Rage | Aura 77, mechanic immunity value 5 (Fear) | `32768` (`0x00008000`) | Grants Fear immunity and carries the purge flag |
| 46924 Bladestorm | Aura 147, mechanic-immunity mask value 1733; calculated amount is zero | `32784` (`0x00008010`) | Carries the purge flag; the pinned core maps this zero-amount mask to Fear and Stun immunity |
| 49039 Lichborne | Aura 77, mechanic immunity value 5 (Fear) | `163872` (`0x00028020`) | Grants Fear immunity and carries the purge flag |
| 48792 Icebound Fortitude | Aura 77, mechanic immunity value 12 (Stun) | `0` | Stun immunity, but this source row does not prove active-aura purge |
The selected rows used by the runtime proof also require these exact raw values:
| Spell | Attributes0 | Attributes1 | Attributes3 | Attributes5 | Raw immunity effect |
| --- | ---: | ---: | ---: | ---: | --- |
| 18499 Berserker Rage | `327696` | `32768` | `0` | `0` | Effect 0: aura 77, misc 5 (Fear), raw base points -1, die sides 1 |
| 46924 Bladestorm | `327696` | `32784` | `1024` | `512` | Effect 1: aura 147, misc 1733, raw base points -1, die sides 1 |
`SPELL_ATTR1_IMMUNITY_PURGES_EFFECT` is `0x00008000` in `SharedDefines.h:422`. On applying an immunity aura with a mechanic mask, `SpellInfo::ApplyAllSpellImmunitiesTo` removes existing auras matching that mask when the flag is set (`SpellInfo.cpp:2488–2537`). The pinned core maps Bladestorm's 1733 mask with zero calculated amount to a mask that includes both Fear and Stun (`SpellInfo.cpp:2355–2377`). Thus Berserker Rage and Bladestorm are concrete imported examples of active shout removal: Berserker Rage covers Fear; Bladestorm's sourced mask covers Fear and Stun. The shout rows themselves do not set this purge attribute.
The cast exception is narrower than the aura grant. Berserker Rage has no `Attributes5` allow-while-stunned/fleeing/confused bit, yet its Fear aura and purge flag let the core's `Spell::CheckCasterAuras` ignore active Fear-mechanic auras during its cast check (`Spell.cpp:6830–6978`). That includes the `20511` child: although its effect is stun, its applied aura carries spell-level Mechanic=FEAR, so the core skips that whole aura before the stun-state check. A standalone stun aura remains blocking. Bladestorm has `Attributes5=512` (`EXTRA_INITIAL_PERIOD`), not an allow-while-stunned or allow-while-fleeing flag; it cannot start while feared or stunned in this source path, even though its applied aura later grants both immunities.
## Evidence and implementation boundary
The ignored [parsed source audit artifact](../artifacts/enemy-control-followup-2026-10-06/source-audit.json) retains the parsed generated rows, raw Spell.dbc attribute words, and raw effect fields for the cited WoW 3.3.5a spells. The bounded helper in [enemyControlImmunityPurge.ts](../src/game/enemyControlImmunityPurge.ts) accepts only the exact selected WoW rows and fails closed on unknown profiles, IDs, raw flags, or aura scalars. It distinguishes direct Fear from Bladestorm's Fear-and-Stun grant, records that only Berserker Rage is usable while feared, and scopes cleanup to the four named shout source auras. Since each shout has spell-level Mechanic=FEAR, the Fear purge removes the named 20511 child aura as a whole, including any rider bundled into that runtime aura. A separate generic stun remains active and can keep the target controlled; Icebound Fortitude stays outside the purge path because it has no raw purge flag.
Party AI uses the same selected Berserker Rage proof to escape a named shout Fear, or its Fear-mechanic 20511 stun. It preserves learned-rank selection, target validity, cooldown, GCD, and costs. The context check requires active action-blocking control auras on that companion to be covered by the named source shout proof, so an unrelated generic stun blocks the escape. The broad Magic hit/resist/deflect helper remains unsupported because the full source inputs are absent.
Focused verification passed: the immunity helper, direct-grant integration, and party escape integration tests (19 tests across 3 files). No build, release check, or live run was performed in this scoped task.
@@ -0,0 +1,39 @@
# Enemy control runtime follow-up — 2026-10-06
Shield Bash's missing Daze, safe source-informed fear movement and source-proven immunity escape/purge are integrated. The level-80 cap, Ready-five certification scope and existing loot behavior remain intact. All 126 focused checks across 15 files pass; Ready-five adds seven Vitest and twenty Python checks. The final 8 GB TypeScript/Vite build, asset audits and release-bundle verification pass.
## Behavior and ownership
- `wow335ShieldBashDaze.ts` registers child 29703 for the exact selected WoW335 Shield Bash 72 parent and ordinary source NPCs. It applies a 50% movement slow for six seconds. Source mechanic 11 is **SNARE**, despite the Dazed display name. Snare/physical-school immunity rejects the child; parent interruption remains independent. Full parent blocking/avoidance suppresses the trigger. CoA/RoM parents, unbound ranks/procs and excluded defenders cannot borrow it. The generated playable Shield Bash chain has one rank, 72, through level 80.
- `enemyFearMovement.ts` and `enemyFearMovementRuntime.ts` implement deterministic destination selection within the pinned core's distance/path/retry ranges, live caster lookup, actor-local goal caching and the five-path-failure fallback. They are source-informed simulator policy, not exact server paths or RNG.
- PlayerRig follows accepted waypoints through the existing collision controller and gravity. PartyPopulation follows approved navigation at normal actor speed, including forced movement under Stop. Source fear cannot enable catch-up speed or stuck-recovery relocation. Shorter overlapping stun/confuse/root/sleep auras hold movement even when fear owns the longest timer. Voluntary movement/jumping and ordinary attacks/casts stay blocked.
- `enemyFearSummonMovement.ts` moves mobile owned summons only on a loaded graph with approved projection, LOS, path and bounded steps. The real combat tick suppresses actions while source fear remains. Pet Prowl and actor-local source speed are retained; totems/zones remain stationary.
- The WoW generator retains raw Attributes1/5 and imported apply-aura scalar signatures. `enemyControlImmunityPurge.ts` proves only exact Berserker Rage 18499 and Bladestorm 46924 grants. Applying the proven grant removes whole named FEAR-mechanic shout auras 5246/19134/20511/29544, including bundled riders, while retaining unrelated controls. Player/party Berserker Rage can escape the covered source fear or 20511's FEAR-mechanic stun. Other stuns, cooldowns and GCD still block it. Bladestorm has no controlled-casting bypass. Icebound Fortitude has no sourced active-purge flag.
The matching source and limitations are in [the Daze import](WOW335_SHIELD_BASH_DAZE_2026-10-06.md), [fear audit](ENEMY_FEAR_MOVEMENT_2026-10-06.md) and [hit/immunity audit](ENEMY_CONTROL_HIT_IMMUNITY_FOLLOWUP_2026-10-06.md). Historical sources were read only.
## Verification
The focused report is `artifacts/enemy-control-followup-2026-10-06/focused-vitest.json`: 126/126 checks, 15 files, zero failures. It covers actual player casts and companion completion/AI, parent blocking and dispatch gates, movement expiry, missing/blocked navigation, overlapping controls, accepted immunity grants and authoritative party control state. The rejection fixtures temporarily perturb the canonical learned catalog and restore it in `finally`; those are synthetic source-gate fixtures, not live casts from another game profile.
GPT-6 Luna extra-high handled immunity proof/party escape and the read-only runtime review. Both finished; the reviewer found no actionable runtime bugs. The Daze and fear workers hit Luna capacity, so root completed their remaining implementation/integration and verification. No higher-tier subprocess was used. Root also repaired generated TypeScript emission/type declarations needed by concurrent native-lighting edits; the six native-lighting sanity fixtures passed once those inputs settled. This is not a new native balance certification or a claim of ownership over the concurrent lighting feature.
The final build SHA-256 is `2ded1eedcf7cfb60d53f6c82a33c088c05ff4d881bb258852c035df94770c8d1`. Build output and all referenced content objects were copied and hash-verified before the final one-boss Cellblock Rush run. The earlier content freeze could not be reused because the shared manifest changed.
## Final Cellblock Rush evidence
Run `20261006-172609059`, shared run ID `83b375bf-95bd-4afb-8ac1-7438b7a9d13f`, selected Hamhock through normal Bite-Sized selection: entry 1717, actor/spawn `creature-79098`. Native required and killed IDs both contain exactly that boss. The results overlay records **1/1 in 03:09.7**, with zero player/party deaths and four companions alive. The UI-created Discipline Priest used isolated pre-entry level-30 preparation, ordinary controls and read-only telemetry; no combat-state writes or Boss Testing were used. Seven ordinary healing windows were accepted and effective, totaling 2,444 effective player healing with zero recorded overheal. The owned helper, server and browser completed and cleaned up.
The committed-state recorder retained **797 consecutive events, IDs 9–805**, with zero gaps, errors or discarded events. It records 70 NPC hand results and 161 player/party hand results. Three actual party Shield Bash parent results, IDs **574, 659 and 777**, immediately precede accepted child 29703 aura grants **575, 660 and 778** on Hamhock. This is live dispatch/application evidence; no retained slow-state sample measures the six-second duration or half-speed movement. Those values are established by the actual runtime fixtures. Two Disarm windows contain four actor-hand results; utility snapshots include two Disarm, 38 Wound and nine Bloodlust observations. Offhand, Thrash, block and source-shout applications are unobserved in this seed. Fear locomotion and immunity escape/purge remain focused-runtime evidence, not credited live shout demonstrations.
Root visually inspected the real roster, equipped-party, route-50 and results PNGs under `campaign/final-build-20261006-172611414/`. Player and companion bodies, robe/shoulders and staff/shield/weapon silhouettes render; close stair clustering limits individual companion gear identification. `bite-sized-stormwind-stockade-boss-arrival.png` shows the native results overlay, despite its historical filename. Nine PNGs actually exist. Camera-drag paths declared by the route are absent from that list and from disk, so this run supplies no live camera-drag proof. The unchanged look behavior has 33 passing input regressions. There are zero page exceptions; the only browser console error is a favicon 404.
The fresh snapshot is `artifacts/enemy-control-followup-2026-10-06/frozen-20261006-172147833/`. It contains 5,967 build files (118,392,707 bytes) and a complete copied content manifest, version `content-2160be7ff070205b`, SHA-256 `85fc9f1c504c82aa794806b8a634596a07b34ba63e0bf66530243fe76e2d0356`. All 27,587 referenced objects (6,568,369,443 bytes; 21,605 logical entries) were verified before QA. Build and content fingerprints remain unchanged before/after the run. Root's labeled audit rehashes every frozen build file, seven loaded chunks and all 2,124 actually served manifest objects (77,019,550 bytes), then checks event continuity, boss identity and native completion; it passes with zero integrity failures. Recorded successful URLs/status metadata match immutable local sources. Raw network response bodies were not retained, so independent response-body hashing is not claimed.
The live record, utility events and root integrity audit are under `playtest-artifacts/stockade-weapon-utilities/20261006-172609059/`. Historical full-clear field names certify only the entered one-boss slice. No gameplay source changes or additional live runs followed the freeze.
The Luna extra-high evidence-review subprocess completed an independent read-only check of the captured run, matching the seeded boss/native result, unchanged fingerprints, root integrity audit, event continuity and three Daze grant pairs. It also confirmed the absent slow-state/camera evidence and the results image's historical filename. One adjacent event timestamp pair, IDs 714/715, runs backward by 1 ms; event IDs remain distinct and consecutive, so timestamp monotonicity is not claimed. Final game release hygiene, including untracked paths, and the task's separate vault diff/text checks pass. Canonical feature/workflow notes are updated and the worklog is closed.
## Remaining boundaries
General shout Magic miss/resist/deflect needs fuller original-caster, active-spell, defender and configuration inputs; no guessed roll was added. None-class aura-only children keep their source distinction. Other utility ranks/profiles and immunity grants, remote actor authority, hostile-NPC exact flee behavior, general aura-state immunity, Deterrence siblings, the private Ascension stance DUMMY consumer and exact source Targorr Thrash timing remain gated. Native/CoA builds stay Needs Testing. No full Stockade campaign, Wailing live test, staging, commit or deployment is part of this pass.
@@ -0,0 +1,52 @@
# Enemy Damage Types Audit — 2026-10-03
## Scope
This audit follows imported enemy attack damage type data from the WoW 3.3.5a and RuneWaker source catalogs into `EnemyAttackDefinition`, normalization, and combat hit resolution. It records verified source channels separately from HealerMan's single-school runtime representation. It does not claim complete native damage formula coverage.
## Findings
The two games use separate numeric spell namespaces. Runtime source lookup is therefore keyed by `(damageOrigin, spellId)`: `wow335` is matched only against the WoW Spell.dbc export, and `runewaker` only against the RuneWaker spell catalog. RuneWaker NPC identity is the imported template/NPC ID (`runewakerNpcId`); it must not be confused with a WoW `serverEntry`.
For WoW, `scripts/dungeon-pipeline/compile-campaign-catalog.mjs` now retains Spell.dbc `DmgClass` (field 213) and `SchoolMask` (field 225) on parsed source rows and generated enemy attacks. Runtime `attackKind` follows DmgClass where known: 1 → spell, 2 → melee, 3 → ranged. The compact source exporter reads only spell IDs referenced by compiled campaign attacks and WoW boss mechanics, and retains rows with a recognized harmful damage effect. The effect set currently includes 1, 2, 7, 9, 17, 31, 58, 62, and 121. It excludes non-damaging script records even when their DBC school is populated; for example, Call Flames (48258) and Ritual of the Sword (48331) keep authored runtime typing.
`src/game/mobDamageTypes.ts` converts the seven recognized WoW SchoolMask bits into an ordered list without selecting a “strongest” school. A singleton mask can supply `school`; a composite or unknown mask retains the authored school fallback because combat mitigation still resolves one school per event. Two generated composite examples are Crystalfire Breath (48096, fire + frost) and Death's Bite (67808, frost + shadow). The source list preserves both values, but current combat does not apply two simultaneous school-mitigation passes.
For RuneWaker, packet class, hit-gate type, and resistance channel are separate source values. `MagicProcess.cpp` branches on `MagicBase.Attack.CalType` for direct damage at line 2322 and again for hit/critical handling around lines 3478–3757. The verified direct packet mapping is CalType 0/3/9 → physical and 1/10 → magical; runtime delivery is 0/9 melee, 3 ranged, and 1/10 spell. Other types (including Throw 2, Fix 4, SpecialAction 7, and FixPer 8) remain unclassified by this compact damage-type layer. They keep raw source metadata and are not guessed into a physical/magical packet class. `MagicCollect.EffectType` is inspected separately for the physical-vs-magic hit gate (`MagicProcess.cpp` around line 1648), while raw `MagicObject.EffectType` is retained for effect semantics; neither is used as the direct packet-class field.
`MagicResistENUM` in `SourceCodeVS2019/Libraries/Union/RoleData/ObjectStruct.h` identifies `MagicType` -1 as physical and values 0–5 as Earth, Water, Fire, Wind, Light, and Darkness. The compact catalog keeps this exact `sourceChannel`, independently of `calculationType`: physical remains physical, Earth/Wind → nature, Water → frost, Fire → fire, Light → holy, and Darkness → shadow. The seven-school runtime values are compatibility approximations; the original channel and component ID remain available. Component-specific resolution requires `componentId` whenever a source spell has mixed component classes or channels.
Two imported counterexamples demonstrate why the old `MagicObject.EffectType` interpretation was wrong. Holy Seal (spell 490149, component 500142) has CalType 0, raw EffectType 0, and MagicType Light (4): it is a physical melee packet on the Light/holy channel. Dark Energy Strikes (spell 498602, component 621306) has CalType 1, raw EffectType 1, and MagicType Darkness (5): it is a magical spell packet on the Darkness/shadow channel. Deadly Water Pressure (490045, component 500056) has unsupported CalType 8; it retains Water/frost, but its packet class is left unclassified. The standard spell catalog now applies the same source-derived class, school, attack kind, and normalized `runewakerEffectType` (0 magic, 1 physical) policy; raw component effect types remain in source metadata.
`scripts/runewaker-pipeline/build-population.mjs` stamps imported attacks with `damageOrigin: "runewaker"`, the source runtime `attackKind`, and `runewakerEffectType`. Classification is not inferred from the mapped school: a magical projectile can still be ranged. WoW attacks are stamped `damageOrigin: "wow335"` with raw DmgClass and SchoolMask. `normalizeEnemyAttack` uses source records only when the source row contains recognized damage components, so script/control placeholders do not replace manually-authored schools.
## Periodic damage coverage
The enemy combat runtime now supports authored `kind: "dot"` attack effects. Application creates a dispellable magic debuff, schedules the first pulse at one interval after cast resolution, and resolves each pulse through the ordinary school mitigation and absorb path. Pulses do not roll a fresh hit, miss, crit, dodge, parry, or block. The final pulse may occur at the aura's exact natural-expiry timestamp. A magic dispel removes future scheduled pulses for that target.
The focused integration test exercises an enemy Frost DoT against both the player and a party NPC: no damage at cast start or application, one-second pulses, exact-expiry final tick, and cancellation of the player's remaining ticks after a magic dispel. This verifies the scheduler and event school path. It does not claim that source-native RuneWaker DoT amount snapshots are wired to every NPC yet; those require an exact imported NPC/source-skill/component binding and the native formula's additional source/target inputs.
## Source provenance and generated data
- Current compact export contains 1,653 WoW candidate IDs, 671 WoW damage-spell rows, and 471 rows with direct-damage effect 2. It also contains 3,199 RuneWaker catalog spells and 1,342 exported source spells with 1,398 direct-HP-damage components. Of those components, 512 map to physical packet class, 284 to magical packet class, and 602 have an unsupported/unclassified CalType (including types 2, 4, 7, and 8). The WoW exporter excludes RuneWaker-origin boss mechanics before looking up numeric IDs in the DBC.
- WoW binary source: local WotLK 3.3.5a `Spell.dbc` at `../wow-pvt-server-backups-2/wow335a/Data/patch-A.MPQ/DBFilesClient/Spell.dbc`; SHA-256 `57011d528fd66cf39f5ab6fb168e389ab9e4cc1b8050f7201a54239d489b415c`, 234 fields and 936-byte rows.
- WoW field layout reference in the exporter: AzerothCore `DBCStructure.h`; fields consumed are DmgClass 213, SchoolMask 225, and Effects 71–73.
- RuneWaker source enum: `SourceCodeVS2019/Libraries/Union/RoleData/ObjectStruct.h` (`EM_MagicAttackCalBase` around line 3967 and `MagicResistENUM`). Direct packet and hit/critical dispatch are in `SourceCodeVS2019/Server/NetGameServer/MainProc/MagicProc/MagicProcess.cpp` (direct formula around line 2322, hit/crit dispatch around lines 3478–3757; `MagicCollect.EffectType` hit gate around line 1648). The generated spell snapshot and compact catalog preserve the source calculation type, raw effect type, channel, and component identity.
- RuneWaker spell source catalog: `scripts/runewaker-pipeline/snapshots/runewaker-npc-spell-catalog.json`; current SHA-256 `8a6a5a1629db66dd8df02a559ed01c0f5f746a5bb2112093b5223474be5997ed`.
- Regenerate compact source metadata with `node scripts/dungeon-pipeline/export-enemy-damage-types.mjs` after refreshing source spell catalogs.
## Focused verification
The focused run passed 26 tests across `mobDamageTypes.test.ts`, `enemyDamageTypes.integration.test.ts`, `enemyAttacks.test.ts`, and `enemyCasting.test.ts`. The tests include actual RuneWaker catalog counterexamples and confirm that exact component metadata replaces stale imported attack kind/school during normalization; the integration suite also records Frostbolt and RuneWaker physical-hit events plus the authored periodic lifecycle described above.
## Formula-specific follow-up
The compact exporter also preserves `directFormula` and `formulaMitigation` separately from packet class, raw component EffectType and resistance channel. Exact NPC-bound CalType 4/8 direct packets now use `romNativeEnemyDamage.ts`; the formula's source absorber does not imply a physical/magical packet class or generic DEF/resistance pass. CalType 2 remains source-audited but has no exact imported NPC binding or post-combat-table completion hook. See [the manual enemy formula audit](ROM_NATIVE_ENEMY_DAMAGE_SOURCE_2026-10-03.md) and [the encounter/pressure report](ROM_NATIVE_ENEMY_ENCOUNTER_PASS_2026-10-03.md).
## Remaining limits
- Runtime mitigation still stores one school per damage event. Composite WoW masks are source-preserved and currently use the catalog's authored single-school fallback in combat.
- RuneWaker CalType 2/4/7/8 and any other unmapped calculation type do not receive a packet class in this exporter. Exact manual CalType 4/8 consumers use the separate formula metadata; unsupported formula/source branches retain their authored fallback.
- RuneWaker channel-to-runtime-school translation is approximate by design; retain raw channel/effect type for future exact resistance work.
- Native RuneWaker enemy DoT amount resolution is source-bound, not name-derived. Until the matching binding and required inputs exist for an NPC spell, its authored generic periodic amount remains the documented fallback.
- Unclassified DBC effect IDs, non-damage/script effects, unknown school-mask bits, source rows absent from the local databases, and effect/component interactions outside the importer scope remain authored or unsupported rather than guessed.
+115
View File
@@ -0,0 +1,115 @@
# Pinned enemy equipment mapping — 2026-10-06
## Result
Recovered the exact AzerothCore `creature_equip_template.sql` at the currently
pinned world commit and added its hash-checked fixture and importer path. The
generated reference now joins imported spawn GUIDs and selectors to equipment
sets, then to Item.dbc class and inventory type. The runtime helper resolves
only an explicit source spawn GUID and entry; unknown, mismatched, unsupported,
or unresolvable assignments produce no equipment contract.
The recovered SQL is
`dungeon-pipeline/source-fixtures/azerothcore-4d9d1d4b5723e819c5c390f6ca1177283dbfb8e3/creature_equip_template.sql`.
It hashes to `877205c149fd447b08f0ff2c65976f20c862cd42f068a6fcc294a76c7108936a`
and belongs to AzerothCore commit
`4d9d1d4b5723e819c5c390f6ca1177283dbfb8e3`, matching the active
`creature.sql` and `creature_template.sql` pins. Its schema is
`CreatureID, ID, ItemID1, ItemID2, ItemID3, VerifiedBuild`; the source contains
10,854 SQL rows. The importer checks the full file hash before publishing the
equipment mapping and records it in `azerothCoreSourceLock.json`.
## Imported runtime scope
`azerothCoreReference.json` stores three related mappings under
`creature.equipment*`:
- `equipmentAssignmentsBySpawnGuid[guid]` records the source `id1`, optional
alternate entries `id2`/`id3`, and original `equipment_id` selector.
- `equipmentTemplatesByEntry[entry][equipmentId]` records raw source item IDs
and the three virtual item IDs retained after core loader validation.
- `equipmentItemsById[itemId]` stores the pinned Item.dbc `itemClass` and
`inventoryType` for IDs referenced by those equipment rows.
These assignments cover the source dungeon maps imported by the pipeline, not
all 149,879 rows in the world spawn table. The current generated snapshot has
13,277 spawn-GUID assignments, 755 equipment entries, 763 equipment sets, and
442 referenced item IDs. The spawn selectors are 7,632 zeroes, 5,637 ones, two
twos, and six `-1` values. Twenty-three spawn rows have alternate creature
entries. All 1,034 nonzero virtual item slots in this imported scope resolve
through the pinned Item.dbc and pass its hand-inventory validation.
The Item.dbc input is the WotLK 3.3.5a client file at
`../wow335a/Data/patch-A.MPQ/DBFilesClient/Item.dbc`, SHA-256
`22061a811523790ddd2ee95b36ade2ac6e0c79a8b3121324d32a639acf50567f`. Its
46,149 rows use eight 4-byte fields per 32-byte record; Class is field 1 and InventoryType is
field 6. The importer rejects a different hash or DBC layout. Both pins and
field indexes appear in the generated source lock and reference.
## Source behavior and selectors
The source behavior was checked against the exact commit-pinned
`Creature.cpp` (SHA-256
`ea19df5312b632bb7b9faf4323c1612fff8d8104e390d7193bae584318e3e11b`) and
`ObjectMgr.cpp` (SHA-256
`e4eae029cc30f84c26c258ba806d39eea61200f623aead1ee0813f6adebeed37`).
The relevant operations are `ObjectMgr::GetEquipmentInfo`,
`ObjectMgr::LoadEquipmentTemplates`, spawn data loading, `Creature::LoadEquipment`,
and `Creature::HasWeapon`.
For a database spawn, selector `0` means no equipment. A positive selector
looks up that exact equipment ID. Selector `-1` chooses a random row from the
entry's equipment map, then mutates the selector to `distance(begin, row) + 1`.
That is an ordinal-based ID, not the selected row's actual key. ObjectMgr checks
nonzero alternate entries using the mutated selector and clears the assignment
if a required alternate row is absent; the later creature load again looks up
the concrete ID. The runtime helper mirrors this sequence with an injected
uniform value in `[0, 1)`. It fails closed if the resulting exact lookup or any
alternate lookup is absent rather than choosing the row's key as a substitute.
This distinction matters for sparse IDs. The pinned table has creature 32239
with only equipment ID 2. Its one-row `-1` selection rewrites to ID 1, so a
later ID-1 lookup has no result; the helper will not grant its ID-2 equipment
under a random selector. An explicit selector `2` can resolve that row. The
focused test covers this ordinal-plus-one behavior.
`ObjectMgr::LoadEquipmentTemplates` also removes missing items and item rows
whose Item.dbc InventoryType is not one of `13, 14, 15, 17, 21, 22, 23, 25,
26` (weapon, shield, ranged, two-handed weapon, main-hand weapon, off-hand
weapon, holdable, thrown, or ranged-right). The importer applies this same
whitelist to all three virtual slots. After that validation,
`Creature::HasWeapon(OFF_ATTACK)` in AUTO mode checks the resolved Item.dbc
`ClassID == ITEM_CLASS_WEAPON` (2). No `item_template` lookup is needed for
that gate; this import does not claim to model item stats or item damage.
The helper `enemySpawnEquipmentContract(entry, sourceCreatureGuid, randomUnit?)`
returns the resolved virtual item IDs and offhand class, plus the existing
`autoOffhand` contract when the offhand item is a weapon. It requires a source
GUID whose imported entry list contains the requested creature. Database
spawns with selector zero resolve to empty virtual slots. Missing GUIDs,
synthetic spawns, entry mismatches, older references without equipment maps,
and failed selector lookups return no contract. Core's separate no-spawn-data
default `LoadEquipment()` selects ID 1; the GUID-based helper does not infer
that creation path for synthetic actors.
The mapping only supplies source equipment and AUTO offhand capability. It
does not schedule attacks, import item stats, change loot, alter the level-80
cap, or certify CoA/native balance. Ready-five remains the certification set;
CoA and native balance remain Needs Testing.
## Validation
- `node --test scripts/dungeon-pipeline/import-azerothcore-world.test.mjs` — 10
focused tests passed.
- `npx vitest run src/game/enemyEquipment.test.ts` — 7 focused tests passed.
- `node scripts/dungeon-pipeline/import-azerothcore-world.mjs --item-dbc
"F:\\Projects\\wow335a\\Data\\patch-A.MPQ\\DBFilesClient\\Item.dbc"` —
green; 54 imported dungeon snapshots, 13,277 creature spawns, 494 encounters,
with the three expected Ascension-only fallback maps.
The isolated source-data subprocess did not run a production build or live QA.
Root's combined continuation subsequently passes the standard build, Ready-five,
avatar checks and the one frozen Cellblock Rush clear. Targorr's live source
GUID 84027 resolves virtual slots `[5305, 5305, 0]` and weapon Class 2; eight
offhand outcomes are observed. Combined evidence and limitations are in
[the continuation report](ENEMY_SOURCE_PARITY_CONTINUATION_2026-10-06.md).
+56
View File
@@ -0,0 +1,56 @@
# Enemy Dual Wield and Thrash source contract — 2026-10-05
src/game/enemyExtraAttacks.ts owns the pinned Spell.dbc contracts and source-shaped helper behavior for creature Dual Wield (674/29651) and Thrash (3391). It does not schedule enemy abilities or mutate combat state.
## Client spell rows
The exact client sources are:
| Profile | Spell.dbc | SHA-256 |
| --- | --- | --- |
| Ascension | ../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc | 2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce |
| Epoch | ../HealerMan-Storage/pipeline-work/dungeons/epoch-client/DBFilesClient/Spell.dbc | d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3 |
Both profiles identify Dual Wield spells 674 and 29651 as effect 40 (SPELL_EFFECT_DUAL_WIELD) with implicit target A = self, raw effect base points 0, no die-side roll, and no damage packet. Spell 674 has Attributes0 336 in Ascension and 80 in Epoch; spell 29651 has Attributes0 80 in both. Spell 674's damage class is 1; 29651's is 0. Both are durationless.
Spell 3391 Thrash is effect 19 (SPELL_EFFECT_ADD_EXTRA_ATTACKS), implicit target A = self, with raw EffectBasePoints = 1 and EffectDieSides = 1. The compiler's base-point convention stores 2 because it normalizes raw base points by adding one. Historical core SpellEffectInfo::CalcValue instead starts with raw BasePoints = 1 and adds one for DieSides = 1, yielding exactly two extra attacks. The contract preserves raw and normalized values separately; do not interpret the normalized 2 as a second die roll.
The matching generated compiler descriptors are in scripts/dungeon-pipeline/compile-campaign-catalog.mjs near lines 1167–1183. Generation already classifies these as utilities rather than direct damage.
## Creature Dual Wield behavior
The read-only historical AzerothCore reference implements effect 40 in src/server/game/Spells/SpellEffects.cpp (Spell::EffectDualWield): only on HIT_TARGET it calls SetCanDualWield(true) on the effect target. For creature units, that enables the offhand attack channel; it does not itself deliver an attack.
When Dual Wield is enabled, a creature does not need an equipped offhand item for the core offhand channel to exist: `Creature::HasWeapon(OFF_ATTACK)` returns true in enabled mode (`Creature.cpp:3299`). Core creates the same generated min/max base weapon range for BASE_ATTACK and OFF_ATTACK in `Creature::SelectLevel`, using `CreatureBaseStats::GenerateBaseDamage`. `Creature::CalculateMinMaxDamage` in `Entities/Unit/StatSystem.cpp` then applies the same template variance, AP contribution, damage modifier, and attack-speed math to either hand. Core's default `UNIT_MOD_DAMAGE_OFFHAND` total-percent modifier is 0.5 (`Unit.cpp:401`), so the offhand uses half of its otherwise-equivalent creature damage formula. `Creature::UpdateEntry` assigns `CreatureTemplate.BaseAttackTime` to both hands (`Creature.cpp:617–618`). They have separate swing timers; the creature melee AI can add a 200 ms presentation stagger when both are ready together. The initial offhand timer is offset to half a base swing on attack start.
Core's ordinary weapon swing miss calculation adds 19 percentage points while dual wielding (`Unit.cpp:15276`, `MeleeSpellMissChance`, when `spellId` is zero and an offhand is available). Enabled creature offhands satisfy that availability check without an item row, so the penalty applies to their mainhand, offhand, and queued mainhand swings. The runtime applies it only to ordinary creature weapon swings, preserving native/player-defender exclusions.
The source effect only sets the creature capability; it has no aura duration and the core source does not remove it when the caster leaves combat. This simulator clears the capability, timer, and queued swings on its death, navigation/leash, and encounter-reset lifecycle as game policy. That reset behavior is not claimed as an exact spell-expiration rule from the core. RuneWaker actors, summons, and character defenders remain outside this source-creature path. The separate `flags_extra` `USE_OFFHAND_ATTACK` and AUTO virtual-item cases are not modeled here.
This formula is core-owned and does not justify copying an already rolled mainhand hit as the offhand hit. Runtime damage should apply the offhand modifier to the generated creature range/AP formula before the ordinary hit-table and defense resolution. For creatures that have not entered enabled Dual Wield mode, the historical core's AUTO mode does require a valid offhand weapon. The locked Healer-Man world source includes creature rows with equipment_id but not the equipment-template table, so that missing mapping must not be guessed.
## Thrash behavior
Core `Spell::EffectAddExtraAttacks` queues its calculated count only when the effect is handled on HIT_TARGET and the target unit is alive. `Unit::Update` clears `_lastDamagedTargetGuid` before draining already queued swings (`Unit.cpp:561–575`). Ordinary mainhand/offhand updates set it to their victim even when mitigation leaves zero damage (`Unit.cpp:2827`); direct spell damage writes it only when source damage is positive (`Spell.cpp:2774`); periodic aura ticks do not write it in this source. `Unit::AddExtraAttacks` captures that current-update target, or the unit's selected target if there is no last-damaged GUID; with neither it queues nothing. The saved queued target remains fixed through the next update. On the next `Unit::Update` queue-drain phase, `HandleProcExtraAttackFor` issues one BASE_ATTACK (mainhand) melee update per queued count (`Unit.cpp:2934–2945`). Ordinary Thrash swings are discarded if the target is gone or outside melee range when drained. They go through the normal melee attack outcome and mitigation path; they are not offhand swings and do not replace or reset the normal mainhand swing timer.
Thrash has a fixed count of two, not a random proc chance. The normal melee proc machinery still handles those swings. The core aura proc filter blocks the same ADD_EXTRA_ATTACKS spell from chaining itself while it is the current extra-attack source; other melee effects keep their own source eligibility rules. Runtime should preserve this bounded same-spell recursion behavior without disabling unrelated melee procs.
## Current Stockade source cases
The locked creature_template_spell.sql data lists spell 3391 for Targorr the Dread (1696) and spell 29651 for Bazil Thredd (1716). The SmartAI table casts 674 for three Stockade creatures, always targeting self with an initial 1000–1000 ms update interval and zero repeat interval:
| Entry | Creature | Raw SmartAI event type | Meaning in the core enum | Evidence |
| ---: | --- | ---: | --- | --- |
| 1696 | Targorr the Dread | 0 | update in combat | SQL comment incorrectly says out of combat |
| 1711 | Defias Convict | 1 | update out of combat | SQL comment agrees |
| 1716 | Bazil Thredd | 1 | update out of combat | SQL comment incorrectly says in combat |
SMART_EVENT_UPDATE_IC = 0 and SMART_EVENT_UPDATE_OOC = 1 are defined in the historical SmartScriptMgr.h. Prefer these raw event types over the inconsistent Targorr/Bazil SQL comments. Targorr's template lists Thrash, but the locked Stockade SmartAI rows contain no cast action for spell 3391. That source establishes availability, not a Thrash cadence; do not invent one.
The source lock for the world import pins creature.sql, creature_template.sql, creature_template_spell.sql, and smart_scripts.sql, but not an equipment-template mapping. The historical AzerothCore checkout used for behavior references has HEAD e822d718322289dd036fb2daf8867ba41283bf9a; it is read-only reference material and is not represented as the exact server-code revision named by the world source lock.
## Runtime integration surface
Import `enemyDualWieldContract(spellId, sourceProfile)` to validate a 674 or 29651 effect and obtain the explicit offhand formula/timing contract. `enemyThrashContract(sourceProfile)` supplies the exact two-swing, queued mainhand semantics; `resolveEnemyThrashTarget(lastDamagedId, selectedId)` implements core target precedence and returns null when neither target is known. Unknown spell/profile pins fail closed. `trackEnemyLastDamagedTarget` models the current-update source target writers and deliberately ignores periodic ticks.
Runtime integration in `combatStore.ts` keeps the offhand timer independent of the mainhand's cooldown, drains each saved Thrash target/count before selecting the next cast, gives every hand/swing a distinct deterministic seed, and routes each packet through ordinary hit, mitigation, and proc handling. The offhand starts at half the base swing after engagement; Bloodlust retimes in-flight weapon clocks without changing queued extra attacks or spell cooldowns. Preserve the same-spell extra-attack recursion guard. Do not promote unsupported enemy data into loot, readiness, or all-class balance coverage.
+141
View File
@@ -0,0 +1,141 @@
# Enemy fear movement follow-up — 2026-10-06
This pass integrates source-informed movement for the pinned enemy shout fear
auras into player, party and mobile owned-summon consumers. Voluntary movement,
jumping, attacks and casts remain suppressed while fear controls the actor.
Movement requires reviewed navigation and collision/LOS approval. Missing or
blocked spatial support safely holds the actor. Other controls retain their
existing policy; this does not claim exact historical-server path or RNG parity.
## Historical core behavior
The read-only historical source is AzerothCore commit
`e822d718322289dd036fb2daf8867ba41283bf9a`, specifically
`src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp`,
`src/server/game/Movement/MotionMaster.cpp`,
`src/server/game/Entities/Unit/Unit.cpp`, and
`src/server/game/Spells/Auras/SpellAuraEffects.cpp` under
`../wow-pvt-server-backups-2/azerothcore-wotlk`.
`HandleModFear` passes the live aura caster to `Unit::SetControlled`; that
passes it to `SetFeared`, then `MotionMaster::MoveFleeing`. The generator looks
up the caster GUID when it chooses each new destination. It does not preserve
the caster's cast-time position. If that lookup fails, it picks a random angle
and follows its near-source distance branch with a source distance of zero. A
dead caster can still resolve while its unit remains in-world; after removal,
the source-less fallback applies.
The source's exact movement bounds and retries are:
| Core rule | Source value |
| --- | ---: |
| Quiet-range lower bound | 28 yd |
| Quiet-range upper bound | 43 yd |
| Minimum accepted path | 2 yd |
| Path length limit | 30 yd |
| Retry after destination LOS failure | 200 ms |
| Retry after failed, short, or invalid path | 100 ms |
| Repath wait after spline travel | random 800–1500 ms |
Below 28 yards, the server picks a distance between `0.4` and `1.3` times the
remaining distance to 28 yards and a heading within ±π/8 of the direction away
from the source. Above 43 yards, it picks `0.4`–`1.0` times the 15-yard band
width and heads partly back toward the source, within ±π/4. Inside the quiet
band, it picks `0.6`–`1.2` times the band width in a random direction. A source
distance at or below 0.2 yards uses a random base angle. The core constrains the
candidate with `MovePositionToFirstCollision`, checks LOS to the resulting
point, then asks `PathGenerator` for a path and rejects shortcuts, no-path,
far-from-poly, paths shorter than 2 yards, and paths beyond the 30-yard limit.
After five failed paths it stops looking up the source and uses the
source-less random fallback.
`SetControlled` does not start fear while stun or confusion already owns the
unit. When the higher-priority control ends, it rechecks active fear auras and
resolves their caster GUID. This helper accepts the actor's active stun end time
and holds fear movement until that higher-priority control expires.
## Planner boundary
[`src/game/enemyFearMovement.ts`](../src/game/enemyFearMovement.ts) carries the
source distance bands, steering ranges, LOS/path retries, and path length
limits. Its hash-based choices are simulator decisions: they reproduce the
source's ranges with stable values derived from actor ID, source ID, aura
application time, and decision index. They do not reproduce the core's global
random-number stream. `worldUnitsPerYard` is required input because imported map
coordinates can have a different scale. The estimated time to the next choice
uses approved path length divided by this actor's current effective speed,
then adds a seeded wait from the core's 800–1500 ms range.
Each actor supplies its own fear expiry, stun expiry, base movement speed, and
source speed multiplier. The shout's +25% speed is therefore applied only when
that target has the still-active source speed aura. The current adapters are
limited to tagged source fear. `getSourcePosition` runs once per repath so
the goal uses the live caster location at that decision; the caller should
cache the resulting goal until `nextDecisionAtMs` instead of recomputing it
every frame.
The planner requires three map adapters: a projection that rejects excessive
snaps and floor changes, an LOS test, and a complete actor-safe path-length
query. Missing map support, an unsafe projection, blocked LOS, or an invalid
route yields a hold with the source retry timing. The destination is a route
goal only. The caller must move through actor collision and approved navigation
waypoints; it must never assign the destination directly to an actor position.
`stepEnemyFearTowardDestination` only computes a bounded request and does not
replace those checks.
## Integration seams before this pass
- `PlayerRig` resolves the player's shout control near its frame movement step.
`enemyControlPreventsMovement` currently blocks all fear before movement, and
`Rapier`'s character controller checks the player's capsule against terrain.
For a tagged source fear with no active stun, the frame can use the cached
flee goal to set the autonomous world movement vector, then submit its bounded
delta through the existing character controller. The goal must not be
derived from camera input or change camera yaw.
- `PartyPopulation` similarly blocks fear before companion route planning. It
already has the reviewed navigation graph, `planPartyRoute`, direct-segment
collision checks, and route-segment clearance validation. A fear goal should
use those route helpers and hold when no safe route exists.
- The summon loop in `combatStore.ts` returns early when `controlledUntil` is
active, before movement and actions. `CombatSummon` currently keeps a control
expiry but no control mechanic. A source fear adapter needs to preserve the
per-summon fear and stun state, move only when fear is the active control,
and continue to suppress actions. `CombatSpatialProvider` provides live actor
positions, LOS, ground projection, and the reviewed navigation graph; the
adapter still needs to validate a complete route before advancing a summon.
- The shout control resolver currently returns only mechanic and expiry. The
integration must identify the active tagged `ActiveAura` per actor to retain
its source ID and `appliedAt` for live source lookup and deterministic seeding.
That lookup can use the mob runtime position while the caster exists; when
the source ID no longer resolves, pass `null` and use the source-less branch.
The existing hostile NPC fear path is separate. `MobPopulation` already calls
`stepFearedMobAway` and clamps that direct step to the home leash, using the
current aggro target as the threat. That helper does not perform LOS or route
validation for the flee step. This follow-up leaves it unchanged and does not
claim it matches the historical generator.
## Integrated consumers and verification
`enemyFearMovementRuntime.ts` retains the selected aura's source/application,
caches each goal and implements the five-failure source fallback. Concurrent
tagged stun and generic stun/confuse/root/sleep auras hold movement even when
the actor's longest control timer belongs to fear. Expiry or purge clears the
per-actor goal; a refreshed aura starts a new decision sequence.
PlayerRig follows approved route waypoints through its existing Rapier character
controller, including gravity. Keyboard movement and jumping do not steer fear.
PartyPopulation uses its reviewed graph and capsule route validators, normal
party speed with actor-local source modifiers, and follows forced fear even
under Stop. Fear never enables catch-up speed or stuck-recovery relocation.
Camera look retains its ordinary hold-and-drag behavior.
`enemyFearSummonMovement.ts` requires a loaded graph and validates projection,
LOS, path segments and each bounded step. The actual combat tick consumes it
before summon actions, holds concurrent controls, and preserves the pet's Prowl
movement modifier. Totems and stationary zones remain stationary. Remote actor
authority and hostile-NPC flee policy remain outside this bounded integration.
Focused planner/cache/summon verification passes 20 tests, including actual pet
ticks, blocked/missing navigation and simultaneous stun expiry. Input regressions
pass 33 tests. Final build/live evidence is recorded in the combined follow-up report.
@@ -0,0 +1,64 @@
# Enemy hit source inputs — 2026-10-07
The enemy damage source exporter now preserves the raw WoW attribute words that
the pinned 3.3.5a hit-result path checks before miss, avoidance, and deflect
resolution. The work adds source inputs only; the runtime consumer owns how
these flags affect hit resolution.
## Pinned source and field mapping
The WoW source is the local 3.3.5a `Spell.dbc` at
`../wow-pvt-server-backups-2/wow335a/Data/patch-A.MPQ/DBFilesClient/Spell.dbc`.
Its SHA-256 is
`57011d528fd66cf39f5ab6fb168e389ab9e4cc1b8050f7201a54239d489b415c`;
the verified layout is 234 fields and 936-byte rows.
The pinned AzerothCore `src/server/shared/DataStores/DBCStructure.h` maps
Spell.dbc field 4 to `Attributes`, field 7 to `AttributesEx3`, and field 11 to
`AttributesEx7`. `SpellInfo.cpp` copies those DBC words to the corresponding
server fields. `SharedDefines.h` identifies the relevant source bits:
| Field | Core bit | Core meaning |
|---|---|---|
| `Attributes` (4) | `SPELL_ATTR0_NO_ACTIVE_DEFENSE`, `0x00200000` | Prevent physical avoidance |
| `AttributesEx3` (7) | `SPELL_ATTR3_ALWAYS_HIT`, `0x00040000` | Ignore hit result |
| `AttributesEx7` (11) | `SPELL_ATTR7_NO_ATTACK_MISS`, `0x02000000` | Spell cannot be missed |
In the pinned `Unit.cpp`, `MeleeSpellHitResult` returns early for
`SPELL_ATTR3_ALWAYS_HIT` and `SPELL_ATTR0_NO_ACTIVE_DEFENSE`; the latter follows
the miss check and precedes resist, avoidance, and deflect handling.
`MagicSpellHitResult` returns early for `SPELL_ATTR3_ALWAYS_HIT` and
`SPELL_ATTR7_NO_ATTACK_MISS` before its ordinary hit/deflect checks. The exact
raw attributes remain available so the runtime can follow these source gates.
## Data path and limits
`scripts/dungeon-pipeline/export-enemy-damage-types.mjs` reads fields 4, 7, and
11 into a structured `hitSource` object for each exported WoW damage row. It
records explicit zeros when the matched DBC row contains zero. The generated
catalog records these source field indexes in
`generatedFrom.wowSpellHitFields` and the pinned DBC hash above.
`src/game/mobDamageTypes.ts` carries `hitSource` only from a matched `wow335`
source spell. `src/game/enemyAttacks.ts` copies the same object to
`wowHitSource` during normalization. Unknown spell IDs have no source object;
RuneWaker rows remain in their separate numeric spell namespace and do not
receive WoW hit metadata.
This metadata does not define complete WoW hit, miss, resist, dodge, parry,
block, or deflect tables. Those outcomes and their ordering remain in the
combat runtime. Non-damage/script rows excluded by the exporter, unknown DBC
spells, and native/RuneWaker attacks remain without this WoW source object.
## Focused checks
- `node --test scripts/dungeon-pipeline/export-enemy-damage-types.test.mjs`
builds a small WDBC fixture and proves fields 4/7/11 are read independently,
including a real zero-valued raw word.
- `npx vitest run src/game/mobDamageTypes.test.ts` checks the generated WoW
metadata through resolution and attack normalization, and verifies absent
metadata for unknown and RuneWaker source lookups.
The exporter can target a temporary JSON path with `--output` for its focused
fixture; the production output remains
`src/game/generated/enemyDamageTypeSources.generated.json`.
@@ -0,0 +1,139 @@
# Enemy shout speed and immunity audit — 2026-10-06
This follow-up pins the parent movement-speed effect and the immunity-related
source scalars for Intimidating Shout `5246 -> 20511` and Frightening Shout
`19134 -> 29544`. The earlier
[`ENEMY_TRIGGERED_SHOUTS_2026-10-06.md`](ENEMY_TRIGGERED_SHOUTS_2026-10-06.md)
remains the targeting and timed-control reference. The runtime attaches the
sourced speed modifier and tag to the existing parent control aura, and both
player and party movement consume that target-local multiplier. Shout target
selection also includes eligible owned summons, but the current summon action
loop holds a controlled summon before its movement step. The +25% speed is
therefore sourced on that recipient without changing its movement during the
shared fear/control lifetime; no fear-flee behavior is claimed.
## Client source rows
The Ascension input is
`../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc`,
SHA-256
`2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce`. The
Epoch input is
`../HealerMan-Storage/pipeline-work/dungeons/epoch-client/DBFilesClient/Spell.dbc`,
SHA-256
`d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3`. Both
use the shared patch-S `SpellDuration.dbc` and `SpellRadius.dbc` fallbacks
recorded in `enemySourceAuras.ts`.
Raw `Spell.dbc` field 3 (`Mechanic`) is 5 on all four rows, which the selected
core defines as `MECHANIC_FEAR`. Effect-level `EffectMechanic` is 0 on every
effect. `DamageClass` is field 213; `Dispel` is field 2. The attribute tuple
below lists raw fields 4 through 11 in order (`Attributes0` through
`Attributes7`):
| Spell | Profile | Spell mechanic | Damage class | Dispel | Attributes0–7 |
| --- | --- | ---: | ---: | ---: | --- |
| 5246 parent | Ascension | 5 | 1 (Magic) | 0 | `[0, 0, 0, 0, 0, 0, 0x02000000, 0]` |
| 20511 child | Ascension | 5 | 1 (Magic) | 0 | `[0, 0, 0, 0x00090000, 0x00800000, 0, 0, 0]` |
| 19134 parent | Ascension | 5 | 1 (Magic) | 0 | `[0x00050010, 0, 0, 0, 0, 0, 0, 0]` |
| 29544 child | Ascension | 5 | 0 (None) | 0 | `[0, 0, 0, 0, 0, 0, 0, 0]` |
| 5246 parent | Epoch | 5 | 1 (Magic) | 0 | `[0x00050010, 136, 0, 0, 0, 0, 0x00800000, 0]` |
| 20511 child | Epoch | 5 | 0 (None) | 0 | `[0, 0, 0, 0, 0, 0, 0, 0]` |
| 19134 parent | Epoch | 5 | 1 (Magic) | 0 | `[0x00050010, 0, 0, 0, 0, 0, 0, 0]` |
| 29544 child | Epoch | 5 | 0 (None) | 0 | `[0, 0, 0, 0, 0, 0, 0, 0]` |
None of these rows sets `ATTR0_NO_IMMUNITIES`, `ATTR2_NO_SCHOOL_IMMUNITIES`,
`ATTR3_ALWAYS_HIT`, `ATTR4_NO_PARTIAL_IMMUNITY`, or
`ATTR7_NO_ATTACK_MISS`. The source does not mark a spell as always hitting or
as bypassing immunity. Both parent casts are Magic-class rows. Child 20511 is
Magic class only in Ascension; 20511 in Epoch and child 29544 in both profiles
are `DamageClass=None` aura-only rows. The historical core routes Magic-class
spells through its magic hit calculation and applies its ordinary aura-only
handling to None-class rows. The HealerMan runtime does not implement the
general hit, resist, or deflect calculation in this pass.
## Parent speed effect
Both parents have effect 2 `APPLY_AURA` (`effectType=6`) with aura 31
`MOD_INCREASE_SPEED`, base points 25, target A 22 (`TARGET_SRC_CASTER`),
target B 15 (`TARGET_UNIT_SRC_AREA_ENEMY`), and radius index 14 (8 yd). Thus
the aura grants +25% movement speed to eligible hostile recipients in the
same caster-centered 8-yard area as parent fear. Its duration follows the
parent row:
| Parent | Ascension | Epoch |
| --- | ---: | ---: |
| 5246 Intimidating Shout | 5 s | 8 s |
| 19134 Frightening Shout | 4 s | 6 s |
`enemyTriggeredShoutMovementSpeedEffect` exposes this only when effect 2 still
matches the source aura, amount, target pair, radius, and area contract. Its
modifier uses the ActiveAura fraction (`0.25`) and the tag
`enemy-triggered-shout:parent-movement-speed`. The target-local multiplier
helper ignores expired, permanent, differently targeted, and untagged auras;
if multiple shout speed effects are active it returns the strongest positive
bonus, matching the historical core's `GetMaxPositiveAuraModifier` handling
for `SPELL_AURA_MOD_INCREASE_SPEED`.
The runtime stores the speed modifier on the existing per-target parent
`enemy-control:source-spell-5246` or
`enemy-control:source-spell-19134` aura. This keeps same-caster refresh,
different-caster preserve-existing behavior, and caster-removal persistence
with the parent control record. PlayerRig and PartyPopulation movement consume
the target-local multiplier. The summon loop currently returns for the
parent's active control before moving, so this pass does not introduce summon
movement or fear-flee AI. The control and speed effects share one duration. The
table gives the DBC duration baseline; historical core
`Spell::DoSpellHitOnUnit` computes one duration for the shared aura, then
`Unit::ModSpellDuration` derives mechanic duration modifiers from the complete
spell, including its spell-level fear mechanic. A fear-duration modifier can
therefore shorten the combined fear and speed aura together.
The runtime attaches the speed modifier only when it accepts the parent spell
application. This is important for fear immunity: the source rows have
spell-level `Mechanic=5`, and the historical core checks that mechanic in
`Unit::IsImmunedToSpell` before resolving the per-effect aura immunities.
`Unit::SpellHitResult` calls that whole-spell check. Under the runtime's
whole-spell fear-immunity policy, a fear-immune recipient does not receive the
parent's fear or +25% speed effect. While fear is active, the existing player
and party locomotion policy blocks movement; the speed multiplier is tracked
on the shared aura but does not override that fear movement policy.
## Child control and immunity behavior
Child 20511 has aura 12 (`MOD_STUN`) for 5 seconds in Ascension and 8 seconds
in Epoch. Ascension also has a separate aura 87 effect that increases physical
damage taken by 15% for 5 seconds; Epoch has no such rider. Child 29544 has
only fear aura 7, for 3 seconds in Ascension and 6 seconds in Epoch.
The whole-spell fear mechanic applies to all four rows. A fear mechanic
immunity therefore rejects the parent or triggered child as a whole in the
selected core. A stun-state immunity is narrower: it filters child 20511's
aura-12 effect. In Ascension the separate aura-87 physical damage-taken rider
can remain; Epoch's 20511 row has no remaining child effect. The source
children have `Dispel=0`, so neither is dispellable by category. The same
source-caster refresh and different-caster preserve-existing policy remains in
`applyEnemySourceAura`; the shared parent control aura IDs already survive
caster removal. Recipient removal removes the combined fear and speed aura.
## Targeting and implementation boundary
The parent effect-0 trigger remains a separate cast on its explicit victim;
the child is not selected from the area list. Effects 1 and 2 remain the
independent caster-centered area pair at 8 yards, with the existing cap of 5
for 5246 and unlimited (`MaxAffectedTargets=0`) for 19134. A qualifying
explicit victim may also receive the area effects. The prior targeting report
documents the separate LOS rules, overlap, and random-ordering boundary.
Historical AzerothCore sources were read-only under
`../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/game/Spells/` and
`../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/game/Entities/Unit/`.
The relevant paths are `Spell::EffectTriggerSpell`,
`Spell::AddUnitTarget`, `Unit::IsImmunedToSpell`,
`Unit::IsImmunedToSpellEffect`, `Unit::SpellHitResult`,
`Unit::MagicSpellHitResult`, and `Unit::UpdateSpeed`. The current simulation
still does not model general magic hit/resist/deflect rolls or creature-specific
exceptions. The level-80 cap, loot, readiness, and publication scope are
unchanged.
Focused verification passed: `npx vitest run src/game/enemyTriggeredShouts.test.ts src/game/enemySourceAuras.test.ts` (2 files, 12 tests). The root-owned shout integration suite also passed during integration; the owner runs final repository checks after shared changes settle.
@@ -0,0 +1,21 @@
# Enemy Silence Cast Gate — 2026-10-04
## Finding
Lady Anacondra's imported spell 8148 is Thorns. The generated Wailing Caverns reference records it as a cast-targeted Nature aura from SmartAI row 4 (`Lady Anacondra - In Combat - Cast Thorns`): `school: nature`, `delivery: melee`, `animation: cast`, and `effect.kind: aura`. The source entry has no `attackKind` or `damageClass`. Since `enemyAttackKind` falls back to `melee` for `delivery: melee`, the previous selection rule (`silenced && attackKind === "spell"`) allowed Thorns to start while Silence was active.
The same Lady Anacondra reference contains spell 9532 Lightning Bolt as a Nature projectile cast from SmartAI row 1 (`Lady Anacondra - In Combat - Cast Lightning Bolt`). Existing active-cast handling already cancels nonphysical casts when Silence takes effect.
## Runtime change
Enemy attack selection now rejects an attack during Silence when its school is nonphysical or its resolved attack kind is `spell`. This uses school and attack kind only for silence eligibility. It leaves shared attack-kind and damage-roll classification unchanged, allows physical melee and ranged attacks, and still suppresses a physical-school attack explicitly classified as a spell.
## Focused coverage
`src/game/enemyCasting.test.ts` uses Lady Anacondra's generated source entries for Thorns 8148 and Lightning Bolt 9532, plus the imported physical melee Tendon Rip. It checks that Lightning Bolt cancels when Silence lands, Thorns neither starts nor resolves over repeated advances in the 8.4-second window, Thorns starts and resolves after Silence expires, physical melee and ranged attacks remain eligible, and physical spells remain blocked. The imported NPC ability data has no separate silence-prevention field; for Thorns it also carries no `attackKind` or `damageClass`, so the test exercises the exact school/delivery ambiguity from source.
The selection test stages a Silence status directly to isolate NPC cast behavior. The separate full Vow of Silence scenario remains the end-to-end validation path for applying the actual player ability and observing its combat result.
## Validation
`node_modules/.bin/vitest run src/game/enemyCasting.test.ts src/game/romPriestChampionRuntime.test.ts src/game/wailingCavernsParity.test.ts` passed: 3 files, 30 tests. Use the direct Vitest binary for this focused workflow; `npm test` invokes the `pretest` loot-generation hook. No build or repository-wide test suite is part of this narrow change.
@@ -0,0 +1,157 @@
# Enemy source parity continuation — 2026-10-06
## Result
Ordinary source NPC defense consumes target-local block chance, ignore-hit-direction,
and critical-block aura inputs. Successful ordinary and post-hit blocks roll the
source integer critical-block chance independently, doubling block value on success.
Player/party auto damage events carry their actual weapon hand, and the QA recorder
projects those results onto committed Disarm windows.
Imported Intimidating Shout 5246 and Frightening Shout 19134 now use separate
explicit-victim child and caster-centered area targeting. The parent cast retains
its captured victim through threat changes and rechecks eligibility, range and LOS
at release. The area uses an inclusive 8m 3D radius without a separate LOS check,
and 5246 caps its shared area selection at five. The eligible explicit victim can
also receive the area aura. The child/parent controls remain independently stored;
their longest active timer governs control, with stun winning equal expiry ties.
All four source rows have Dispel 0. A different caster preserves an existing copy;
same-caster recasts refresh it. Timed recipient auras survive caster removal.
The Ascension 20511 child also applies its sourced +15% physical damage taken.
Epoch has no such rider. The compiler checks parent and child DBC signatures,
trigger links, cap, attributes and Dispel before emitting the new descriptor.
Catalog regeneration changes six attack effect descriptors across four dungeons
and adds 11,095 explicit source GUIDs to static spawns and patrol members. All
other catalog data, geometry, health and populations compare equal to the
pre-generation snapshot. `artifacts/enemy-source-parity-2026-10-06/catalog-diff.json`
and `catalog-equipment-audit.json` retain both checks; the compressed catalog
matches the JSON output.
The boss guide describes the distinct victim and area effects.
The exact pinned equipment table is recovered and hash-checked. Its imported
13,277 spawn assignments join source selectors to sanitized virtual item IDs
using the pinned Item.dbc inventory whitelist. An ordinary NPC with a validated
offhand weapon gains AUTO offhand capability, keeps its independent half-delay
timer, and restores that capability after evade/death resets. Source GUIDs travel
from the compiler through population/scene registration and the selected
Cellblock Rush boss clone. Missing or mismatched GUIDs, empty hands, shields,
unsupported selectors and native actors do not acquire AUTO offhand attacks.
Item stats, model attachments and loot are outside this mapping.
## Source boundaries
- Improved Blocking 3419 is a complete supported source import. Critical Block
47294–47296 and Deterrence variants supply reviewed block-input contracts but
remain gated as complete automatic spell imports: their sibling effects are
unsupported. The runtime tests explicitly use block-input fixtures.
- Non-direct full-hit blocking has a bounded source proof for WoW Shield Bash 72.
Its helper proves only the relevant custom-attribute bits for one pinned core
and database snapshot. Utility/status application consumers and other source
profiles remain open; a client DBC alone does not establish absent custom bits.
- Equipment selector zero, exact positive IDs, ordinal-plus-one random selection,
and alternate entry validation use the recovered matching source. Synthetic
actors lack an explicit source GUID and remain unbound; no-spawn-data ID-1
defaults are not inferred. This mapping does not import item damage or stats.
- Hostile-NPC outgoing threat is source-inapplicable to the current enemy target
path. Current eligible recipients are playable player/party actors or owned
summons; a future NPC-vs-NPC path requires a recipient-side threat-list model.
- Parent shout aura 31's movement-speed rider, additional server hit/immunity
exceptions, Ascension stance DUMMY behavior, exact Thrash source cast timing,
native custom gear/rates/prerequisites and wider proc formulas remain open.
Source audits:
[block auras](NPC_BLOCK_AURA_PARITY_2026-10-06.md),
[triggered shouts](ENEMY_TRIGGERED_SHOUTS_2026-10-06.md),
[equipment mappings](ENEMY_EQUIPMENT_MAPPING_2026-10-06.md), and
[threat boundary](HOSTILE_NPC_THREAT_BOUNDARY_2026-10-06.md).
## Validation
- Initial source/hand checks: 90 tests across 17 focused files passed. After
equipment integration, 73 affected helper/runtime/population tests across 10
files passed; these groups overlap and are not additive.
- Importer, compiler pin, actor Disarm evidence and committed recorder checks:
20 Node tests passed. The wrapper's `--prepare-only --bite-sized-stockade`
syntax check passed without starting a server or browser.
- Ready-five: 7 Vitest and 20 Python tests passed. Avatar checks: 56 passed.
No full-suite or all-class sweep was run.
- Independent Luna reviews found no confirmed issue in shared block/shout
integration or source GUID/equipment registration/reset behavior. The new
equipment runtime fixture explicitly requires pinned flags before reading
them, fixing two optional-value errors caught by the first TypeScript build.
- Standard `npm run build` passed after that fix: TypeScript, Vite, environment
audits, static compression and release-bundle verification. The asset audit
has its existing 60 budget exceptions and no regressions. Existing build
prehooks regenerate the same 9-boss/23-item catalog; no loot is wired here.
- Catalog metadata audit: 11,095 source GUID additions, 30 leaf changes within
six reviewed shout descriptors, zero other changes, matching compressed JSON.
The reviewed build is frozen at
`artifacts/enemy-source-parity-2026-10-06/corrected-build-20261006-054606946/`.
All 5,967 build files are verified, aggregate SHA-256
`50f723e4737f01fe82973c1a9c8259a4358179c1df74373b587fa76fb69b44a7`.
The unchanged isolated content copy is reused from the earlier fully verified
freeze: manifest SHA-256
`ac0fa2a867ba0a495c172de2b89532d69b32d56d032482b26020ce2d189f074b`,
27,571 objects, 6,489,632,021 bytes. This freeze rehashes both content manifests
and the complete new build; it does not recopy those unchanged objects.
All subprocesses use GPT-6 Luna with extra-high reasoning. The workspace includes
concurrent changes; no stage, commit or deployment is part of this task. Level
cap 80, existing loot scope and readiness policy remain unchanged.
## One final live check
Run `playtest-artifacts/stockade-weapon-utilities/20261006-054628643/` uses the
frozen build and normal Cellblock Rush entry. The UI-created Discipline Priest
profile receives isolated pre-entry level-30 preparation; four companions are
asserted against the Ready-five set. Gameplay uses ordinary movement, target,
party-command and healing inputs with read-only committed telemetry. No Boss
Testing, combat-state writes, enemy/aura seeding or teleports are used.
The seeded boss is **Targorr the Dread**, entry 1696, source/live actor
`creature-84027`, from source dungeon `stormwind-stockade`. Native killed-boss
progress and the results overlay agree on **1/1** in **03:10.3**. No player or
party deaths are recorded; effective player healing is 2,845.8. This certifies
the entered bite-sized slice, not the five-boss full campaign.
The recorder retains 794 consecutive post-baseline events with zero ID gaps,
sampling errors or capacity loss. Actual NPC weapon results comprise 60
mainhand, eight offhand and four Thrash extra-mainhand outcomes. The latter
retain source spell 3391. Three queued-extra-attack state observations and 89
positive offhand timer observations are also retained; snapshots are not
activation counts. Player/party auto results contribute 162 actual hand events.
Targorr's committed source-equipment snapshot retains GUID 84027, selector/set
1, virtual items `[5305, 5305, 0]`, offhand Class 2 and AUTO capability, including
a pre-engagement state with no armed offhand timer.
Three committed actor Disarm windows contain four such results; their presence
does not independently prove contribution formulas or cast gates. Runtime
regressions provide that bounded coverage.
The seed records three Disarm and 39 Wound aura snapshots. Bloodlust, block and
triggered-shout aura applications are unobserved in this seed; source/helper and
runtime fixtures cover the newly implemented block/shout behavior. These absent
live observations do not certify all spells or encounter variants.
Root visually inspects the desktop roster, dungeon equipment silhouette,
mid-route images and `bite-sized-stormwind-stockade-boss-arrival.png` (which
captures the native results overlay). Player/companion bodies and staff,
shield, sword and dagger silhouettes are visible. Overlap/occlusion limits a
complete per-companion gear inspection. Results clearly show Targorr and 1/1.
No page exceptions occur; the sole outer console item is a favicon 404.
Both build and content manifest fingerprints remain unchanged before/after.
The harness verifies 2,124 actually served hash-addressed, manifest-referenced
content objects with zero integrity failures. Independent Luna audit rehashes
all 5,967 frozen build files, the seven recorded loaded build chunks and all
2,124 served content objects (77,019,550 bytes), with zero failures. Recorded
URLs and successful response metadata agree with those immutable sources; raw
network response bodies were not persisted. Recorder IDs 9–802 are independently
checked as consecutive. Evidence:
`playtest-artifacts/stockade-weapon-utilities/20261006-054628643/independent-evidence-audit.json`.
`npm run release:check` passes 399 changed paths including untracked files.
Game/vault diffs are reviewed separately, and all six task vault notes pass EOF
and trailing-whitespace checks. The worklog is closed; the one owned live helper,
server and browser are cleaned up. No source changes follow the frozen live run.
+145
View File
@@ -0,0 +1,145 @@
# Enemy Defensive and Battle Stance audit — 2026-10-05
This audit covers the Stockade enemy stance casts Defensive Stance 7164 and
Battle Stance 7165. Their form auras are state, not direct damage. The reviewed
profile-specific rows and the ActiveAura-supported subset are in
[`src/game/enemyStances.ts`](../src/game/enemyStances.ts).
## Pinned client rows
The Ascension source is the recipe compiler's pinned 3.3.5a patch-D table:
`../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc`
SHA-256: `2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce`.
Epoch uses the compiler's pinned table:
`../HealerMan-Storage/pipeline-work/dungeons/epoch-client/DBFilesClient/Spell.dbc`
SHA-256: `d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3`.
Both profiles use the compiler's shared patch-S `SpellDuration.dbc` fallback
for duration indices because neither client folder contains that table. Its
SHA-256 is `eeae44ef0185924f3d6ec57ab2701c66566db86e51ab0bae017a9449126eb3a0`.
The two NPC casts have the same Spell.dbc behavior in both profiles:
| Spell | Effect row (`effect/aura/base/misc/trigger`) | Duration | Stance masks |
| --- | --- | --- | --- |
| 7164 Defensive Stance | `6/36/0/18/0` | 180,000 ms | required `0/0`, excluded `0/0` |
| 7165 Battle Stance | `6/36/0/17/0` | permanent (`-1`) | required `0/0`, excluded `0/0` |
Both have range index 1, school mask 1, damage class 0 for 7164 and 2 for
7165, dispel 0, stack amount 0, and Attribute0 327696. Their equipped-item
class is -1 with subclass and inventory masks 0. The direct effects target self
(`targetA=1`, `targetB=0`), use radius index/value 0, mechanic 0, and period 0.
That attribute value does not include AzerothCore's `SPELL_ATTR0_NOT_SHAPESHIFT`
bit (`0x00010000`). The casts themselves therefore have no source stance mask
or “not while shapeshifted” restriction in these rows. This statement applies
to 7164 and 7165 only; it does not infer restrictions for unrelated abilities.
## Server-linked passive rows
The historical AzerothCore form handler links the forms to passive spells in
`src/server/game/Spells/Auras/SpellAuraEffects.cpp`:
- form 18 → Defensive Stance Passive 7376;
- form 17 → Battle Stance Passive 21156.
This is a server-side mapping. Neither stance cast has a nonzero
`EffectTriggerSpell` in either profile. Both child rows have Attribute0 327888,
the passive flag, and zero required/excluded stance masks. Their actual effect
rows differ by client profile:
| Child passive | Ascension patch-D | Epoch client |
| --- | --- | --- |
| 7376 Defensive Stance Passive | `6/87/-10/127/0`, `6/79/-5/127/0`, `6/4/+42/127/0` | `6/87/-10/127/0`, `6/79/-5/127/0`, `6/10/+45/127/0` |
| 21156 Battle Stance Passive | `6/10/0/127/0`, `6/280/0/0/0` | `6/10/-20/127/0` |
Rows use `effect/aura/base points/misc/trigger`. The final value in each row is
zero: these passive rows also have no triggered child spell. A separate player
stance spell such as 2457 is not a substitute for these NPC rows; its own
profile rows contain additional effects and are not the source cast IDs here.
The passive scalar fields are identical in both profiles: dispel 0, duration
index 0, range index 1, school mask 1, damage class 0, stack amount 0,
equipped-item class -1 with subclass and inventory masks 0, and required and
excluded stance masks 0/0. Each active effect is type 6, targets self
(`targetA=1`, `targetB=0`), has mechanic 0, radius index/value 0, period 0, and
trigger spell 0. The helper pins these scalar fields alongside each profile's
effect rows so the campaign compiler can compare the complete child source.
For compiler drift checks, the WDBC scalar field indices are: `Dispel=2`,
`Attribute0=4`, `ShapeshiftMask=12..13`, `ShapeshiftExclude=14..15`,
`DurationIndex=40`, `RangeIndex=46`, `StackAmount=49`,
`EquippedItemClass=68`, `EquippedItemSubclassMask=69`,
`EquippedItemInventoryMask=70`, `DamageClass=213`, and `SchoolMask=225`.
The three per-effect `EffectTriggerSpell` fields are `116..118`; active effect
rows also use `Effect=71+j`, `BasePoints=80+j`, `Mechanic=83+j`,
`ImplicitTargetA=86+j`, `ImplicitTargetB=89+j`, `RadiusIndex=92+j`,
`Aura=95+j`, `Period=98+j`, and `MiscValue=110+j`. In the campaign compiler,
array fields at index 77 or greater shift by six only when a Spell.dbc has at
least 239 fields. Both pinned client tables have 234 fields, so none of these
indices shift for the current Ascension or Epoch data; stance and equipped-item
fields are below 77 and never use that localized-string adjustment.
Aura 79 is percent damage done, aura 87 is percent damage taken, and aura 10
modifies threat. Their `miscValue` 127 covers all schools. The runtime can
therefore apply Defensive Stance's shared `-10%` damage taken and `-5%` damage
dealt in both profiles. Epoch's passive rows additionally supply `+45%` threat
in Defensive Stance and `-20%` threat in Battle Stance. HealerMan already has a
generic `stat: "threat"` resolver used by party and summon threat generation,
so these profile-specific scalars are retained in the helper. Current combat
threat tables record party and summon threat against hostile mobs; hostile NPCs
have no outgoing-threat consumer in the current combat runtime. The two threat
modifiers therefore do not change direct enemy hits, party threat, or the
current threat tables.
Ascension's aura 4 row on 7376 is `DUMMY` with base points +42. No
spell-specific `HandleAuraDummy` case, server script registration, linked spell,
or triggered child was found for 7376, so its meaning is not guessed. Aura 280
on Ascension's 21156 row has base points 0; it has no numerical delta and is
kept as source metadata without an unsupported-effect warning. Aura 10 with
base points 0 on that same row is also a sourced zero. No defensive or battle
stance row is treated as an NPC direct hit.
## Apply, replacement, expiry, and removal
In `SpellAuraEffects.cpp`, applying a new shapeshift removes an existing
shapeshift aura before setting the new form. The form boost handler applies the
mapped passive only when the form changes and removes that owned passive when
the stance aura is removed. The two stances are therefore mutually exclusive;
the helper uses the `enemy-warrior-stance` exclusive group to preserve that
state. Reapplying 7164 refreshes its timed form aura; 7165 remains until another
form replaces it or it is explicitly removed.
When a warrior stance aura is removed, AzerothCore caps Rage to its computed
stance removal value. Player-only spellbook bonuses contribute to that value;
an ordinary NPC has no player spellbook contribution, so the default cap is
zero. On expiry or removal with no replacement stance, the server also clears
the form. The current enemy helper records the sourced form and duration; it
does not invent a creature Rage baseline or treat the passive DUMMY row as
resource regeneration. Its aura uses the shared `enemy-source-spell-<id>` ID
format and carries utility tags for the form and linked passive ID, allowing
existing source-aura cleanup and telemetry to identify it.
## Historical source checked
Read-only reference: `../wow-pvt-server-backups-2/azerothcore-wotlk`.
- `src/server/game/Spells/Auras/SpellAuraEffects.cpp`: form-to-passive mapping,
child aura cleanup, replacement of existing shapeshift auras, and stance Rage
reset on removal.
- `src/server/game/Spells/SpellInfo.cpp`: `CheckShapeshift` reads
`ShapeshiftMask`, `ShapeshiftExclude`, and `NOT_SHAPESHIFT`.
- `src/server/game/Spells/Auras/SpellAuraDefines.h`: aura IDs 4, 10, 79, 87,
and 280.
- `src/server/game/Combat/ThreatManager.cpp`: aura 10 is consumed as a
multiplicative threat modifier by school mask.
- `src/server/game/Spells/Auras/SpellAuraEffects.cpp` and the server scripts
plus SQL update tree: no 7376-specific dummy effect or linked-spell consumer
was found.
The targeted helper tests check both profile rows, exclusivity, supported
damage/threat modifiers, and the permanent versus timed duration. No full test
suite, build, or live combat run is part of this source audit.
+112
View File
@@ -0,0 +1,112 @@
# Enemy stances and NPC blocking — 2026-10-05
The approved continuation implements NPC Defensive/Battle Stance and Improved
Blocking for ordinary source-backed WoW creatures. Separate GPT-6 Luna workers
with extra-high reasoning supplied source helpers, integration tests and live
QA. The level cap remains 80; loot and readiness promotion are outside scope.
`enemyStances.ts` binds NPC forms 18/17 to core-owned passives 7376/21156 using
the selected Ascension/Epoch client. The shared source aura is the only owner
of its stance modifiers. Defensive lasts 180 seconds and multiplies all-school
damage taken by 0.9 and dealt by 0.95. Battle is permanent until replacement or
removal. The exclusive group prevents both forms remaining active. Reset,
evade and expiry remove the owned modifiers. Ascension Battle has zero numeric
child effects but retains its form identity. Epoch threat modifiers are stored
without altering the incoming party threat table; this runtime has no hostile
NPC outgoing-threat consumer. Ascension Defensive's DUMMY +42 remains
unsupported because no source handler was established.
`enemyBlocking.ts` provides an ordinary Creature baseline of 5% plus block aura
percentage points, and block value `floor(level / 2)`. Historical Creature
Strength stays zero; the loaded class-level Strength column is not assigned
to ordinary creatures. This baseline has no equipment/shield requirement.
The shared player/companion damage resolver applies the level-based skill
adjustment once, real target facing, active cast/control and evade gates, and
the pinned template `flags_extra` NO_BLOCK bit. Improved Blocking adds 75
percentage points for six seconds. Its effect expires exactly at the aura
boundary. Native RoM attackers use the same ordinary WoW target defense path;
native RoM defenders and character/summoned defenders retain their own models.
This initial stance pass enables the sourced auto-attack block baseline. The
subsequent [spell continuation](NPC_SPELL_BLOCKING_2026-10-05.md) imports per-rank
defense attributes and enables direct physical spell mitigation for player and
party casts, including crit-plus-block. Periodic and non-direct full-hit spell
blocks remain excluded. Missing source flags, levels outside 1–80 or missing
spatial evidence disable this block baseline. Runtime Totems/Guardians are
outside ordinary-creature scope; template type is not a safe Totem identifier.
Ignore-hit-direction auras are not newly imported by this batch.
The source CONTROLLED set is stun/fear/confuse. The runtime additionally treats
sleep/blind/knockdown/freeze as unable to defend, matching its incapacitation
model; this is a simulator approximation. A plain root still permits blocking.
The world importer now preserves `flags_extra` without changing any other
reference fields: all 1,671 selected templates have an exact mask.
None of the selected masks sets NO_BLOCK; that gate is verified through the
importer fixture and pure helper, rather than claimed as a live Stockade case.
The campaign
compiler validates form and profile-specific child signatures, including raw
duration indices, attributes, equipped-item masks, targets, school masks,
triggers and effect amounts before enabling the three reviewed parent spells.
Both source profiles must be present; fallback cannot substitute one for the
other. Generated JSON and compressed TypeScript are refreshed together.
Reviewed SmartAI self auras preserve one-shot flags and combat timing.
Stockade Inmates apply Battle Stance after one idle second, before the pull;
it is excluded from in-combat selection. Kam Deepfury applies Defensive once
and repeats Improved Blocking on its source schedule. Reset re-arms the idle
schedule. Non-boss SmartAI expansion is restricted to these three self auras.
Catalog comparison against the preserved working baseline changes 14 entities
in seven dungeons, with unrelated attacks, health and placements unchanged.
Focused checks, production build and live evidence are recorded below.
Source details: [stances](ENEMY_STANCES_2026-10-05.md),
[blocking](NPC_BLOCKING_2026-10-05.md). Live report:
[full Stockade](STOCKADE_STANCES_BLOCKING_PLAYTEST_2026-10-05.md).
## Validation
- All 102 checks across the twelve affected Vitest files pass, including actual
imported aura casts, idle preparation, player/companion block results,
exact-boundary expiry, geometry, unsupported packets and source exclusions.
- Ready-five passes seven Vitest and twenty Python checks. The world importer
tests pass seven cases; compiler regeneration passes both strict profiles.
- Independent Luna review confirms formulas, source boundaries, skill applied
once, stance pins and idle timing. Its control-label precision finding is
recorded as the explicit simulator approximation above.
- Production build passes with its content/asset prechecks, 8GB TypeScript/Vite
and compression/release-bundle hooks. An incorrect test type import and a
separate concurrent test's ClassId annotation were corrected before the final
passing build; no runtime behavior changed in those corrections.
- Pre-live release check passes (211 changed paths including unrelated work).
One unrelated file's mixed CRLF/LF was normalized to LF for required hygiene.
Final release check passes 240 changed paths, including concurrent unrelated
work; the count is not a claim that every path belongs to this continuation.
- Frozen full Stockade live validation passes on 5,964 files / 116,405,610 bytes,
aggregate SHA-256
`1fcd021af0ef90c8d994cf1ab853ef0e62f4d4767fa3acaab698b14121194310`.
Mutable dist stayed unchanged during the verified copy; the frozen aggregate
stayed identical before and after live QA.
- Run `20261005-184333429` enters the normal full dungeon as a level-30
Discipline Priest with four Ready companions. The native results screen
confirms all five exact boss IDs, Easy/Normal, at 24:25.4. No observed player
or party deaths or resurrection recoveries occurred; all finish alive.
Natural progression ends at player level 40 / companions 39, within cap 80.
- Live state contains Defensive/Battle and Improved Blocking auras, plus eight
party attacks blocked by hostile NPCs and 141 hostile attacks blocked by the
party. Blocked amounts are retained only for the 33 samples matching the
latest damage event's outcome/raw amount; this is sampled correlation, not
a stronger actor-and-event-linked packet assertion. Remaining outcomes keep
their amount unknown. Deterministic tests supply unobserved boundaries and
melee/player/native-RoM attacker cases.
Reconstruction keys aura applications by instance ID plus application time:
one Defensive, 34 Battle and one preserved Improved Blocking application.
Additional short Improved Blocking applications remain unverified by live
sampling. The corrected wrapper and prepare-only syntax checks pass.
- Root reviewed the 25/50/75-percent scene captures and native full-clear image.
Bodies and weapon/shield silhouettes render; existing overlap/edge occlusion
remains. There are zero page errors and one missing-favicon console 404.
All 2,124 fetched hash-addressed content objects verify. The overall content
manifest changed during the run, so whole-content immutability is not claimed.
The live report records source-provenance and sampling limits, along with the
preserved superseded first attempt.
The run-owned runner/browser have exited and temporary harnesses are removed.
+121
View File
@@ -0,0 +1,121 @@
# Enemy triggered shout audit — 2026-10-06
This report covers only separate-victim child spells from Intimidating Shout
5246 and Frightening Shout 19134. It preserves the existing caster-centered
fear source contract and keeps unsupported source effects explicit.
## Pinned client evidence
The Ascension input is
`../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc`,
SHA-256
`2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce`. The
Epoch input is
`../HealerMan-Storage/pipeline-work/dungeons/epoch-client/DBFilesClient/Spell.dbc`,
SHA-256
`d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3`. Both
use the existing shared patch-S `SpellDuration.dbc` and `SpellRadius.dbc`
fallbacks; Epoch is not represented as carrying untouched sibling support
tables. The matching source pins also live in `enemySourceAuras.ts`.
Direct reads from both `WDBC` inputs confirm raw Spell.dbc field 212 is
`MaxAffectedTargets` (5246 = 5; 19134 = 0) and field 2 is `Dispel` (0 for
both parents and both children). `DamageClass` is field 213; `Attributes2` is
field 6 and is zero on all four rows. The profile signatures below are kept
separate, including Epoch 5246's Attributes1 value 136.
| Parent cast | Explicit child spell | Parent range | Parent area | Area target cap | Parent fear duration: Asc / Epoch | Child control duration: Asc / Epoch |
| --- | --- | ---: | --- | ---: | ---: | ---: |
| 5246 Intimidating Shout | 20511 Intimidating Shout | 8 yd | Caster-centered hostile radius 8 yd | 5 | 5 s / 8 s | Stun 5 s / 8 s |
| 19134 Frightening Shout | 29544 Frightening Shout | 10 yd | Caster-centered hostile radius 8 yd | 0 (unlimited) | 4 s / 6 s | Fear 3 s / 6 s |
Each parent has effect 0 `TRIGGER_SPELL` (effect type 64), target A 6
(`TARGET_UNIT_TARGET_ENEMY`), and the exact child ID shown above. Each child
has target A 6, target B 0. Parent effects 1 and 2 use target A 22
(`TARGET_SRC_CASTER`) plus target B 15 (`TARGET_UNIT_SRC_AREA_ENEMY`) at
radius index 14 (8 yd). The first area aura is fear, aura 7. Effect 2 is aura
31 (`MOD_INCREASE_SPEED`, +25%) and remains unsupported.
Child 20511 is stun aura 12 on both profiles. Ascension also has aura 87
(`MOD_DAMAGE_PERCENT_TAKEN`) for +15% physical damage taken over 5 seconds;
it has no direct damage effect. Epoch 20511 contains only the 8-second stun.
Child 29544 is fear aura 7 only: 3 seconds in Ascension and 6 seconds in
Epoch. It likewise has no direct damage effect. Battle Shout 9128 and
Demoralizing Shouts 16244/13730 have no DBC trigger ID in either selected
profile, so their names do not qualify them for this triggered-child path.
The existing direct aura baseline remains owned by `enemySourceAuras.ts` and
its existing attack-catalog contract. This report does not replace those rows
with the triggered-shout child contracts or claim full implementation of
parent effect 2.
## Targeting and core behavior
The read-only historical source used for the targeting audit is under
`../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/game/Spells/`.
`SpellEffects.cpp` `Spell::EffectTriggerSpell` supplies the parent effect's
`unitTarget` to the child when `NeedsToBeTriggeredByCaster` is true;
`SpellInfo.cpp` returns true when the child requires an explicit unit target.
That establishes one child victim: the parent's explicit hostile victim.
The runtime helper therefore accepts that victim only if the caller's
hostile/range/LOS recheck still considers it eligible. It never chooses a
different secondary target for the child.
The same source's `Spell::SelectEffectImplicitTargets` combines area effects
whose target A/B, implicit conditions and calculated radius match. Here
effects 1 and 2 share the same pair and radius, so one caster-centered area
recipient selection receives their effect mask. `SelectImplicitAreaTargets`
limits that set using `MaxAffectedTargets` when nonzero, then
`AddUnitTarget` merges effect masks when a target GUID already exists. There
is no exclusion of the explicit cast victim from the area result: if it is
also a valid hostile within 8 yards, it can receive both the child and the
parent area aura. Accordingly `planEnemyTriggeredShoutTargets` returns the
eligible explicit child victim separately and preserves the area list
unchanged.
`WorldObjectSpellAreaTargetCheck` applies 3D radius and the base spell target
check; `WorldObjectSpellTargetCheck` applies hostile eligibility. These area
checks do not add a per-recipient line-of-sight test. The parent explicit
victim still follows ordinary explicit-cast checks. Spell.dbc has no
`Attributes2` ignore-LOS flag for these parents. The caller remains
responsible for game-specific visibility/LOS eligibility when forming each
input list; the pure targeting helper does not perform spatial queries.
The area cap applies to the parent area recipients only: 5 for 5246 and no
cap for 19134. The child is a separate triggered cast with one explicit unit
target. No extra max-target cap is applied to the parent's area list, and no
synthetic damage packet is introduced for either child.
## Overlap and lifecycle contract
Parent and child control remain separate named timed auras so control-removal
paths, expiry and caster refresh can retain each sourced timer. The shared utility tag is
`enemy-control-source:<fear|stun>`. Effective shout control is resolved from
currently active tagged auras on the requested target: the aura with the
latest expiry supplies the runtime mechanic/timer, with stun winning an exact
expiry tie. Thus an Ascension 19134 overlap resolves to parent fear through
4 seconds after its child fear expires at 3 seconds; a 5246 child stun wins
when its expiry ties the parent fear. Epoch 19134 ties are both fear, while
Epoch 5246 ties resolve to stun.
All four DBC rows have Dispel 0, so the source does not mark these control
auras as dispellable. The source children have stack amount zero and no
`AURA_UNIQUE` bit in either profile. The project aura policy refreshes an existing same-caster copy and
preserves a different caster's active same-spell application. Removal of a
shout caster retains these four timed control aura IDs on other targets:
`enemy-control:source-spell-20511`, `enemy-control:source-spell-29544`,
`enemy-control:source-spell-5246`, and `enemy-control:source-spell-19134`.
Removing the recipient still removes its auras.
## Boundaries
This source pass does not model parent aura 31's +25% movement speed, immune
target exceptions, creature-specific AoE immunity, random selection ordering
when 5246 has more than five area recipients, or every server/database script
override. Historical SmartAI rows establish source NPC casts but do not change
the DBC target geometry. The runtime's incoming eligible target snapshots
remain authoritative. A client/core difference or changed source pin must
fail the exact signature check rather than broaden behavior by spell name.
Focused verification: `npx vitest run src/game/enemyTriggeredShouts.test.ts
src/game/enemySourceAuras.test.ts`.
@@ -0,0 +1,153 @@
# Enemy utility and control completion — 2026-10-06
## Implemented behavior
Ordinary source Creature self-casts can import Critical Block 47294–47296
through a separate guarded path. The known template, identical caster/target,
complete profile/rank signature and default-core aura 107 applicability proof
are required. Aura107 spell modifiers are no-ops for non-player targets on
that audited default path; aura 253 supplies critical-block chance. The generic
importer and Deterrence remain gated. No source creature assignment was found,
so this pass assigns no new NPC cast. A labeled synthetic runtime fixture
proves permanent application, critical blocking, no damage and reset cleanup.
Exact WoW335 Shield Bash 72 now rolls one ordinary-NPC block stage before the
player and companion utility effect loops. Full blocking cancels the entire
recipient effect list while retaining the accepted cast's cost and cooldown.
A zero-amount cast result carries the block flag; no damage packet is
fabricated. Existing facing, casting, control, no-block, native, summon and
character-defender gates remain authoritative. An actively casting NPC cannot
block, so an unblocked interrupt still uses the existing interruption path.
This stage adds block only; other utility hit/avoidance behavior is unchanged.
Additional ranks, profiles and unknown custom attributes are not inferred.
Source shouts 5246/19134 apply parent aura 31's +25% movement speed alongside
their caster-centered fear. Player and companion movement consume the
strongest active target-local tagged bonus. Fear and speed share the parent
aura's adjusted lifetime, source-caster refresh and caster-removal persistence.
Baseline durations remain 5/4 seconds in Ascension and 8/6 seconds in Epoch.
The source core adjusts one shared parent aura duration; a fear-duration
modifier therefore shortens its speed rider too.
All four parent/child rows carry spell-level MECHANIC_FEAR. Whole-spell fear
immunity rejects their controls and riders before per-effect immunity checks.
Stun immunity alone strips 20511's stun effect while preserving Ascension's
separate +15% physical-damage-taken rider. Epoch has no such physical rider.
Compiler pins now include spell mechanic and all eight raw attribute words;
regenerated campaign JSON is byte-for-byte identical to the starting snapshot.
## Source boundaries
The stance/Thrash audit rechecks four active world tables against both locks
at world commit 4d9d1d4b5723e819c5c390f6ca1177283dbfb8e3, separately from the
read-only historical core e822d718 behavior reference. Ascension passive 7376's
third effect is fixed DUMMY +42, with no recovered handler/registration; the
core correction only suppresses caster procs. It remains metadata-only.
Targorr 1696 is SmartAI. Its three source rows cast 674, cast 8599 at low health,
and talk; no row schedules 3391. The template spell list establishes Thrash
availability, and CombatAI's separate scheduler cannot supply SmartAI timing.
The existing simulator cadence is retained and remains explicitly approximate.
The existing player/party/summon fear policy immobilizes rather than reproducing
source fleeing AI. Eligible summons can receive the source aura, but their
control loop returns before movement for that shared lifetime. General Magic hit/resist/deflect, already-active aura purge
on an unidentified immunity grant, wider utility full hit tables, Deterrence
siblings, native custom equipment/rates/prerequisites and broader weapon/proc
formulas remain separate gaps. The shout rows alone do not prove an immunity
grant's `IMMUNITY_PURGES_EFFECT` flag. Shield Bash retains trigger 29703 in its
parent descriptor, but the Daze child is absent from the runtime catalog;
this pass cancels trigger execution on full block without claiming a live
child application.
Source reports:
[Critical Block imports](NPC_CRITICAL_BLOCK_IMPORTS_2026-10-06.md),
[utility blocking](UTILITY_SPELL_BLOCKING_2026-10-06.md),
[shout speed/immunity](ENEMY_SHOUT_SPEED_IMMUNITY_2026-10-06.md), and
[stance/Thrash audit](STANCE_THRASH_SOURCE_AUDIT_2026-10-06.md).
## Validation
The directly affected helper/runtime selection covers 96 passing tests across
15 files, including the final 15-test shout file and four new actual utility
runtime tests. Runs overlap and are not additive. The player utility fixture
proves one block result, normal completion telemetry, retained cost/cooldown
and no damage. The companion fixture is a synthetic accepted pending cast
completed through the real executor. Casting-defender interruption and all
excluded defender types are covered. Six compiler source-pin Node tests pass,
including all shout attribute words and Critical Block sibling drift.
Ready-five passes 7 Vitest and
20 Python tests, and avatar checks pass 56 tests. The production build passes
TypeScript with 8GB memory, Vite, environment audits, compression and release
bundle verification. Existing prehooks regenerate the same 9-boss/23-item loot
catalog; this task adds no loot wiring. No full suite or all-class sweep runs.
Luna's read-only review finds no confirmed defect in the shared block,
Critical Block, shout or compiler integration. Final utility tests and an
8GB TypeScript check pass after adding their fixtures. No production source
changes follow the final build/freeze.
## One final live check
Run `playtest-artifacts/stockade-weapon-utilities/20261006-141251022/` enters
Cellblock Rush normally with a UI-created Discipline Priest and four Ready
companions. Isolated pre-entry preparation sets level 30; gameplay uses ordinary
movement, targeting, healing and party commands with read-only telemetry.
No Boss Testing, teleports, combat-state writes or enemy/aura seeding occur.
The seeded boss is **Targorr the Dread**, entry 1696, source/live
`creature-84027`. Native killed-boss progress and the visible results overlay
agree on **1/1** in **03:09.2**. No player or party deaths occur. Seven effective
player healing events total 2,337, with 95 overheal. The result certifies this
one-boss slice; the harness's historical full-clear field names do not mean
the five-boss full Stockade campaign was tested.
The committed recorder retains 749 consecutive events, IDs 9–757, with no gaps,
errors, discarded events/states or coverage issues. Source NPC hand results
include 56 mainhand, four offhand and two Thrash extra-mainhand outcomes; the
extra swings retain source 3391. They demonstrate the existing simulator
schedule/effect, not a source-proven Targorr cadence. Player/party hand results
total 172. Three committed Disarm windows contain seven hand results; this
overlap is evidence of actual events, not independent proof of contribution
formulas. Three Disarm and 42 Wound snapshots are observed. Block/shout and
Bloodlust aura applications are unobserved; no live claim is made for them.
Critical Block has no real source creature assignment in this catalog.
Root inspects roster, dungeon equipment silhouette, mid-route and the native
results image (`bite-sized-stormwind-stockade-boss-arrival.png`). Player/party
bodies and staff, shield and blade silhouettes are visible. Overlap and HUD
occlusion prevent a complete per-companion gear inspection. There are no page
exceptions; the sole outer console item is a favicon 404.
The build freeze is
`artifacts/enemy-utility-control-2026-10-06/corrected-build-20261006-140236745/`:
5,967 files, 118,061,079 bytes, aggregate SHA-256
`8cf9513613aa3ef6a0a64de392e90521b0349d85311f930ba8808e868d6867d9`.
The unchanged isolated content copy is reused from the earlier fully verified
freeze: 27,571 objects, 6,489,632,021 bytes, manifest SHA-256
`ac0fa2a867ba0a495c172de2b89532d69b32d56d032482b26020ce2d189f074b`.
The new freeze rehashes the complete build and both content manifests; it does
not recopy unchanged content objects. Before/after fingerprints agree. The
harness verifies 2,124 actually served manifest-referenced hash-addressed
objects with zero integrity failures. Raw network bodies are not retained;
evidence joins recorded URLs/status with the immutable local source files.
The independent evidence-audit follow-up also fails with Luna capacity. Root
runs `root-evidence-audit.cjs` in the current live evidence folder, rehashing
all 5,967 frozen files, seven recorded loaded chunks and all 2,124 served
manifest objects (77,019,550 bytes), with zero failures. It independently
recomputes consecutive event IDs, native one-boss completion, zero deaths and
the error boundary from retained artifacts. `root-evidence-audit.json` labels
this root fallback explicitly; it is not presented as a completed subprocess
audit. No higher-tier subprocess is selected.
All subprocesses use GPT-6 Luna with extra-high reasoning. The utility runtime
follow-up failed because that model was at capacity; root completed its four
tests directly without upgrading a subprocess. Level cap 80,
Ready-five certification and loot scope remain unchanged. The shared workspace
contains concurrent edits; no staging, commit or deployment is part of this
pass. Historical source trees remain read-only.
Final `npm run release:check` passes 478 changed paths, including untracked
files. Game and vault diffs are checked separately; all 13 task documents
pass EOF and trailing-whitespace checks. Canonical notes and the closed
worklog record the implemented behavior and remaining boundaries.
+128
View File
@@ -0,0 +1,128 @@
# Enemy weapon debuffs source audit — 2026-10-05
This note records the source contract for enemy Disarm (6713) and Infected
Wound (17230). The active game uses the selected Ascension or Epoch `Spell.dbc`
profile; the repository compiler's source rows are in
`scripts/dungeon-pipeline/compile-campaign-catalog.mjs`, and the pure contracts
and channel predicates are in `src/game/enemyWeaponDebuffs.ts`.
Character-side Disarm checks are in `src/game/enemyDisarmRuntime.ts`.
## Pinned client rows
The Ascension source is
`../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc`,
SHA-256 `2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce`.
The Epoch source is
`../HealerMan-Storage/pipeline-work/dungeons/epoch-client/DBFilesClient/Spell.dbc`,
SHA-256 `d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3`.
The pinned duration and radius fallback tables are the shared patch-S tables
recorded in `src/game/enemySourceAuras.ts`.
Both profiles define Disarm 6713 as range index 2, physical school mask 1,
melee damage class 2, mechanic 3, duration 5 seconds, zero stacks, no dispel,
and `EquippedItemClass = -1` (no caster weapon requirement). Ascension has
Aura 67 (main-hand) and Aura 278 (ranged); Epoch has Aura 67 only. Aura 254
(off-hand) is absent from both rows. These effects disable only the named
weapon attack channels; they do not silence spell casts. The profile helper
requires the target to have at least one affected usable weapon slot before
application. For a player, an already-disarmed slot is no longer usable for
this check, so a repeated cast may fail before refreshing that slot; a creature
target is checked by the presence of its virtual item slot instead. When a cast
is accepted, the zero-stack aura refreshes its duration. The source-derived
Disarm spell itself applies only after its melee hit result lands.
Both profiles define Infected Wound 17230 as range index 2, Nature school mask
8, damage class 0, duration 300 seconds, zero stacks, Disease dispel type 3,
and no caster weapon requirement. Its single Aura 14 effect has amount +6 and
misc value 1 (physical school mask). Aura 14 adds six flat damage to matching
physical packets; it is not a six-percent modifier. The aura refreshes without
stacking and can be removed by a friendly Disease dispel. As a damage-class
NONE aura-only spell, the AzerothCore hit-result path has no miss/dodge roll
for it after its ordinary immunity/evade checks. A caller modeling it as part
of a separate landed weapon attack must use that attack result as its own gate.
## Historical core behavior
The sibling `../wow-pvt-server-backups-2/azerothcore-wotlk` tree is used only
as read-only behavior evidence:
- `src/server/game/Spells/SpellInfo.cpp` checks the target's matching weapon
channels for mechanic Disarm. Players use a usable equipped weapon; creatures
use virtual item slots. Main-hand, off-hand, and ranged channels are checked
independently.
- `src/server/game/Spells/Auras/SpellAuraEffects.cpp` maps Aura 67 to main-hand,
Aura 254 to off-hand, and Aura 278 to ranged. Applying a channel removes the
player's item-dependent aura and damage contribution, keeps the item
equipped, then sets the corresponding unit flag. Creatures with configured
equipment recalculate their physical damage. Clearing the aura reverses the
temporary weapon changes.
- `src/server/game/Entities/Unit/Unit.h` maps those flags through
`CanUseAttackType`. `Unit::AttackerStateUpdate` does not gate ordinary main-hand
swings on that flag, so the character still makes an unarmed main-hand swing.
`Player::_ApplyWeaponDamage` clears disarmed ranged weapon damage and resets
its delay; for a non-feral main hand it sets base damage to 1–2 and attack
time to 2000 ms while preserving equipped item stats. Feral forms return
before that weapon reset. `Spell.cpp` chooses
melee `m_attackType` as main-hand by default or off-hand when the spell has
`REQUIRES_OFF_HAND_WEAPON`; ranged spells use the ranged channel only when
marked as ranged-weapon spells. The source flags for strict main-hand and
off-hand requirements are Spell AttributesEx3 bits `0x00000400` and
`0x01000000`. NPC `CheckItems` rejects a damage-class melee/ranged spell when
its selected attack channel is unavailable. Player `CheckItems` checks
explicit item requirements through `GetUseableItemByPos`; class `-1` passes
without an equipment gate, while class-2 requirements scan usable matching
weapons across main-hand, off-hand, and ranged slots. A matching off-hand
weapon therefore keeps a generic class-2 requirement usable under Ascension
or Epoch Disarm. For a nonpassive aura spell, the core also preserves casting
when the matching item remains equipped but Disarm made it unusable; the
explicit strict main/off-hand attribute checks still require that slot's
weapon. `Item::IsFitToSpellRequirements` applies class, subclass, and
inventory-type masks.
- `Unit.cpp` applies Aura 14 through `MeleeDamageBonusTaken` for weapon damage,
before armor mitigation. Non-direct spell packets, including periodic packets,
reach `SpellBaseDamageBonusTaken` through `SpellDamageBonusTaken` and get the
flat amount when the aura's misc school mask overlaps. The direct spell
damage path returns before `SpellBaseDamageBonusTaken`, so this audit does not
claim a bonus for ordinary direct magic spells. This aura has no charges, so the core's special
charged-aura DoT exclusion does not apply. The bonus enters before armor
mitigation; melee/ranged spell block follows armor, and damage absorbs resolve
after the damage calculation.
- `Unit::SpellHitResult` sends Disarm's melee damage class through melee miss,
dodge, and parry resolution. Infected Wound's damage class is NONE and its
only effect is an aura, so it does not take that melee result path.
The contract deliberately does not turn Disarm into root, stun, silence, or a
general physical-action lock. Runtime callers own weapon-specific equipment
state, resolved spell hit outcomes, armor/block/absorb ordering, and aura
application/removal.
The player Disarm handler removes weapon-dependent auras and recalculates the
weapon damage contribution while the item remains equipped. It does not call
the item-stat removal routine, so the weapon's equipped STR/AP/stamina
modifiers remain. The helper `enemyDisarmInvalidatesAbilityRequirement` models
explicit spell item class and subclass gates from currently usable equipped
items; it leaves requirements with item class `-1` unblocked and only reports a
Disarm-caused failure when every matching item is in a channel this source row
disables. `enemyDisarmBlocksAbilityCast` adds the core exception for
nonpassive aura casts and the strict main/off-hand flags. Runtime attack checks
derive channels from the unexpired exact `enemy-disarm:<profile>:<slot>` tags;
they never mutate saved equipment or nonweapon stats. Ascension item-requirement
metadata uses the corrected WotLK Spell.dbc fields 68/69/70 (class, subclass
mask, inventory mask). The previous generator read 67/68, which incorrectly
exported class 0 and a subclass value from the class column; regeneration
changed only those three equipped-item fields and the generated timestamp.
WoW-ruleset main-hand auto damage uses the source unarmed 1–2 base and 2-second
delay while retaining character AP and other equipped stats; an unaffected
off-hand remains active, and feral forms keep their form profile. Ranged auto
channels named by the active source profile are suppressed. Native RoM unarmed
damage is left to its existing amount path because no bound core formula was
verified. This pass also does not claim complete removal of all weapon-dependent
item aura bonuses or generic ability formulas that derive damage from raw weapon
stats.
## Focused validation
Run `npx vitest run src/game/enemyWeaponDebuffs.test.ts src/game/enemyDisarmRuntime.test.ts src/game/enemyDisarmRuntime.integration.test.ts`
for profile signatures, target/channel eligibility, refresh/dispel, cast gates,
metadata projection, and pre-mitigation school matching. Player and companion
execution are additionally covered by their focused integration tests.
+154
View File
@@ -0,0 +1,154 @@
# Enemy weapon utilities — 2026-10-05
## Scope
This continuation implements the authorized Bloodlust, Disarm/Infected Wound
and Dual Wield/Thrash groups. Separate GPT-6 Luna extra-high subprocesses own
their source helpers and tests; shared runtime and catalog integration preserve
the existing level-80 cap, loot scope and Ready-five certification.
Routine browser proof uses Stormwind Stockade: Cellblock Rush and records the
actual seeded boss. Full Stockade campaigns remain separately selected.
## Source contracts
| Mechanic | Verified behavior |
| --- | --- |
| Bloodlust 6742 | One selected friendly creature, 30 seconds, +30% melee haste, Magic dispel. No party-wide aura radius. Separate source haste factors multiply: Bloodlust and Enrage give interval factor 100/169. |
| Disarm 6713, Ascension | Five seconds; main-hand and ranged channels. Offhand and casting remain available subject to exact equipped-item requirements. |
| Disarm 6713, Epoch | Five seconds; main-hand channel only. |
| Infected Wound 17230 | Five minutes; Disease dispel; +6 flat physical damage taken before armor, block and absorbs. Its own Nature school does not determine the damage modifier's school. |
| Dual Wield 674/29651 | Non-damaging persistent creature capability. Explicit enabled mode uses the source creature baseline for an independent offhand, with the core's 0.5 damage factor. |
| Thrash 3391 | Two queued main-hand extra swings on the next unit update, separate ordinary hit/mitigation results. The spell itself is not a direct-damage packet. |
The pinned Ascension and Epoch rows, shared support tables, core consumers and
source limitations are in the subprocess audits:
- [Bloodlust](ENEMY_BLOODLUST_2026-10-05.md)
- [Disarm and Infected Wound](ENEMY_WEAPON_DEBUFFS_2026-10-05.md)
- [Dual Wield and Thrash](ENEMY_EXTRA_ATTACKS_2026-10-05.md)
Hamhock's raw SmartAI has a five-second, one-time self Bloodlust event with
`SMARTCAST_AURA_NOT_PRESENT`, plus an independent event-16 missing-buff check
within 30 yards and ten-second repeat. The latter selects one engaged living
friendly creature. Targorr's raw Dual Wield event is in combat; Bazil's is out
of combat, despite conflicting SQL comments. Numeric event IDs are authoritative.
Targorr's template lists Thrash but this source set does not supply a SmartAI
Thrash cast schedule. Any retained generic template cadence is simulator policy,
not a recovered source schedule.
## Integration
The compiler emits source-bound utility effects instead of false direct hits.
It retains both sourced Hamhock Bloodlust rules while suppressing the duplicate
template fallback. Ordinary source auras use the shared authoritative aura
array. Disarm state uses explicit channel tags; it does not become a blanket
crowd-control state or remove equipped items. Weapon damage masking is temporary;
non-weapon item stats and persisted equipment remain intact.
The WotLK ability importer had exported equipment metadata from fields 67/68.
Independent raw Spell.dbc probes establish fields 68/69/70 for item class,
subclass mask and inventory mask. The scoped refresh must preserve all other
rank fields, including costs, effects, progression and spell-defense metadata.
Classic Ascension equipment metadata requires the same field correction.
The metadata-only CoA refresh compares parsed current input/output before its
write, allowing only the three equipment fields and synchronization timestamp.
No persistent pre-refresh snapshot was retained; the former dirty working tree
cannot now be independently reconstructed from HEAD. The final formatting-only
rewrite was separately checked for parsed equality.
Timed direct Bloodlust, Disarm and Infected Wound auras on another actor survive
caster death/removal or return-home cleanup. Removing the recipient and resetting
the encounter still clears them. Existing cleanup for other aura families stays
outside this change. Disarm target eligibility uses currently usable resolved
weapons, so an unavailable weapon cannot refresh the debuff.
WoW-ruleset unarmed main-hand autos retain the core's 1–2 base, two-second delay,
AP and other item stats. This includes RoM characters using WoW compatibility.
Native RoM unarmed amounts, complete weapon-dependent aura removal and permitted
generic weapon formulas remain source/runtime limits. Explicit source utility
support does not supply missing automatic/flag-driven virtual equipment.
The existing enemy-team simulation does not model core faction hostility,
map phase or object-size-expanded range. Selected friendly recipients therefore
use the represented enemy team, engaged/living state, point distance and LOS.
This is an explicit simulator boundary rather than an exact faction search.
## Validation
Completed focused checks cover 360 distinct Vitest cases, five Node cases and
twenty Python cases. Repeated regression runs do not inflate these totals.
| Scope | Result |
| --- | --- |
| Shared aura/source contracts, imported aura execution and Bloodlust (six files) | 32 Vitest |
| Selected source/Stockade campaign assertions | 11 Vitest; 22 unrelated cases skipped |
| Avatar and equipment rendering invariants | 56 Vitest |
| Shared combat results, stance/block/spell metadata and native exclusions (eight files) | 57 Vitest |
| Actual imported Disarm application, unusable reapplication and expiry | 2 Vitest |
| Dual Wield/Thrash helpers and imported runtime | 14 Vitest |
| Disarm contracts/runtime/player-party execution plus affected party/combat files | 171 Vitest |
| Actual imported Wound, physical packet kinds, mitigation, Cure Disease and caster removal | 10 Vitest |
| Ready-five | 7 Vitest + 20 Python |
| Equipment-column parser and pinned utility drift | 5 Node |
The standard 8GB TypeScript compilation passes. A default-output build reached
Vite but hit Windows `EPERM` clearing the shared `dist/assets` folder. The same
8GB TypeScript/Vite pipeline succeeds with the isolated output
`artifacts/enemy-weapon-utilities-2026-10-05/production-dist`; standard prebuild
asset audits, precompression and release-bundle verification pass. The shared
build already had a restored index when checked and was preserved.
Earlier test-fixture seed/timestamp type errors were corrected before this build.
The validated output is copied and checked before/after freezing. Its 5,964-file
aggregate SHA-256 is
`58dfe50765b0635caeae50bd3eca2fd079cd69cce0e571ff6cb2dd5aeec77b39`.
Entry is `index-nDB7zewy.js`; combat is `combatStore-NW7YcPHP.js`.
Frozen build/content live under
`artifacts/enemy-weapon-utilities-2026-10-05/frozen-20261006-011726964/`.
Content version is `content-62324661bc5f7a0e`, manifest SHA-256
`36614a23f3b98b4289bc3726c8a9bdb075445ada50dfce6504ade4e36325be1f`.
All 27,571 referenced objects (6,489,458,993 bytes; 21,597 logical files) were
copied and independently verified against their manifest hashes.
The final Luna review found missing attribute pins for 674/29651/3391. The
compiler now rejects profile-specific attribute drift and Thrash die-roll drift;
its three tests pass. Regeneration validates both clients and leaves campaign
JSON and compressed TypeScript byte-identical. Source spell availability does
not establish missing Thrash timing.
Frozen Cellblock Rush run `20261006-012123000` selects Hamhock
(`entry-1717`, `creature-79098`) and verifies its native 1/1 clear in 3:14.6.
The level-30 Discipline player and four Ready companions enter normally; there
are no observed player or party deaths. The build and content manifest remain
unchanged, and all 2,124 served manifest-referenced objects were independently
rehashed by root. The roster, dungeon equipment silhouettes and results capture
were visually inspected. There are no page exceptions; the console records one
`favicon.ico` 404.
This first run's checkpoint projection omits the new weapon fields even though
the live-state reader captures them. All-null summarized weapon state therefore
establishes a harness gap, not an absent game mechanic. The recorder now retains
those fields through the checkpoint reducer and captures the three direct
utility aura IDs globally, including player and party recipients.
Corrected run `20261006-013934624` uses the same frozen inputs and selects
Bazil Thredd (`entry-1716`, `creature-79124`). It verifies the native 1/1 clear
in 3:20.7 without player or party deaths. All 328 mob snapshots retain weapon
fields; 35 show Bazil's Dual Wield capability enabled. All captured offhand
timers are zero, no hand-specific swing is captured, and no nonempty extra
queue is observed. Capability evidence does not establish an offhand hit.
The global aura store supplies 26 snapshots of the tank's single Wound instance,
with four distinct source/application-time tuples. Each is one stack, Disease,
and exactly 300,000 ms; these are four observed applications/refreshes, not
26 applications. Bloodlust and Disarm auras remain unobserved in this retest.
Deterministic imported-runtime tests cover those mechanics and queued Thrash.
Root independently verifies unchanged build/content inputs, all 2,124 served
objects and the actual entry/combat/runtime chunks again, and inspects the
new roster, dungeon and native results captures. No page exceptions; one
favicon 404. Both runs' `root-evidence-audit.json` files retain the audit scope.
Final release hygiene passes, including untracked files; game and vault
changes are reviewed separately. No full-source campaign or readiness promotion
is inferred from these two ordinary one-boss routes.
See [the scoped live report](STOCKADE_WEAPON_UTILITIES_PLAYTEST_2026-10-05.md).
+44
View File
@@ -0,0 +1,44 @@
# Healer mana recovery
A living player or NPC healer now supplies **Healer Mana Recovery** to living
mana users in the local party between fights. The buff restores **15% of each
recipient's maximum mana per second**, in addition to existing recovery. It
supports primary and secondary mana pools, caps at maximum, and does not stack
with multiple healers. It grants no recovery while any living enemy is engaged
or has party threat. Dead recipients and parties without a living healer are
excluded. Native RoM recovery formulas and pulse cadence remain unchanged.
**Pause > Options > Gameplay and interface > Healer mana recovery** toggles
the buff. It defaults to On, including for older profiles missing the setting.
Changes use normal character settings persistence. Turning it off removes
existing applications immediately. The player status panel and mana-using
NPC frames show its icon and tooltip.
## Ownership
- `src/game/healerManaRecovery.ts`: definition, provider selection, recipients,
non-stacking lifecycle, and maximum-mana recovery amount.
- `src/game/combatStore.ts`: saved setting, combat gating, player recovery.
- `src/game/partyRuntime.ts`: companion recovery and shared aura refresh.
- `src/ui/OptionsPanel.tsx`, `src/ui/PartyFrames.tsx`: menu and buff display.
- Native recovery parity tests explicitly disable the convenience aura.
## Verification
136 focused tests pass across the new recovery integration, native recovery
parity, combat store, Options, and AuraStrip suites. Ready-five verification
passes (7 Vitest and 20 Python checks). The final production build, static bundle verification, and release
candidate check pass.
`scripts/playtest-healer-mana-recovery.cjs` enters Cellblock Rush through the
normal dungeon picker using an isolated offline RoM Priest profile. The final
run selected Targorr the Dread, as observed in its live Boss Guide. Pre-entry
profile preparation sets level 30. Ordinary menu clicks switch the buff off
and on; ordinary Urgent Heal spending is followed by natural idle recovery.
Evidence lives in `artifacts/playtest/healer-mana-recovery/`, including loaded
asset URLs, actual selected boss from the live guide, saved toggle state,
resource samples, desktop and 960x540 menu screenshots, and runtime errors.
Exact rate, combat transitions, NPC providers and recipients, no stacking,
healer death, and maximum clamping are verified by focused integration tests.
The browser run is an idle recovery and UI check, not a boss-clear or broader
RoM balance certification.
@@ -0,0 +1,84 @@
# Hostile NPC threat boundary audit — 2026-10-06
## Decision
The `hostile-NPC outgoing threat` item in
[`ACTIVE_CLASS_MECHANICS_BACKLOG.md`](ACTIVE_CLASS_MECHANICS_BACKLOG.md) is not
a missing consumer for the current hostile-mob combat path. HealerMan stores
each hostile mob's incoming target threat on that mob, keyed by the player,
party, online-player, or summon actors that the mob can currently attack. Its
enemy target selector has no hostile mob candidates, and the enemy-hit path
does not write threat into the attacking mob's table. The current model has no
NPC-versus-NPC target boundary to port.
Keep this source-parity item scoped as a future boundary. If hostile creatures
later attack other threat-list-capable creatures, record the attacker in the
recipient creature's threat list after checking that recipient's eligibility.
Do not add outgoing threat to the source mob's own target table.
## AzerothCore holder and direction rules
The read-only behavior reference is AzerothCore HEAD
`e822d718322289dd036fb2daf8867ba41283bf9a`. Its `ThreatManager.cpp` SHA-256 is
`5f8ee4d9c8d9e6d41896b29769f0df315f62d789f2defa29df0a9912002f537b`; its
`Unit.cpp` SHA-256 is
`b7c0c68daee09ec1f863f9a8d6c4972c1adbe35fa5ec230a8887399395db1ed5`.
`ThreatManager::CanHaveThreatList` requires a creature. It excludes pets,
totems, triggers, and player-summoned minions or guardians. `Unit::CanHaveThreatList`
also rejects dead units and vehicles in battlegrounds or arenas. Players
therefore do not own creature threat lists. These are rules about the **list
holder**, not about who may appear as a target in a creature's list: a hostile
creature can still track threat against a player or pet.
In `Unit.cpp:1276`, damage to a non-player victim calls
`victim->AddThreat(attacker, damage, ...)`. `Unit::AddThreat` checks the
recipient (`victim`) with `CanHaveThreatList()` and adds the attacker to that
recipient's threat manager. `ThreatManager::CalculateModifiedThreat` applies
the threat aura multiplier from the threat target passed to that manager,
which is the damage source in this call. Thus damage threat belongs to the
recipient list and is scaled by source-side threat modifiers.
## Current HealerMan path
`MobCombatState` carries `threatByActor`, `targetActorId`, and `forcedTarget`.
`eligibleAggroActorIds` builds candidates from the living local player, living
`PartyMember` records, live online-player actors, and living combat summons;
each must have a position within the hostile mob's leash. `actorPosition`
resolves positions from those same actor sources. The candidate builder does
not enumerate other `MobCombatState` records.
Party records are playable-character builds with class, specialization, role,
level, gear, and talent data. `companionActorFromMember` projects them as
`kind: "companion"`, and `advanceDungeonPartyCombat` runs their combat actions.
They are managed party actors, not unowned AzerothCore creature AI instances.
`CombatSummon` records likewise carry an `ownerActorId` and a pet, totem, or
summon kind. They are valid hostile-mob targets here; that does not make them
threat-list holders.
When a party actor damages a mob, `damageMobInWork` adds threat under the
source actor ID to that damaged mob's `threatByActor`. Healing adds source
threat to each engaged living mob's table. The local threat aura lookup uses
the source actor's aura set before the value is added. `advanceMobCombat`
prunes each mob table to the eligible actors above and resolves that mob's
target from those entries. Enemy attacks then resolve against that selected
actor. The hit handling updates damage, health, and presentation state; it
does not add threat to the attacking mob's own table.
Hostile NPC helpers are also stored as `MobCombatState` entries, distinct from
player or party `CombatSummon` entries. A helper spawn records `summonedBy`;
call-for-help seeds the helper's own table with the same selected party target.
This preserves the current party-versus-hostile-mob model without adding a
mob-to-mob target path.
## Backlog boundary
The current backlog phrase should remain future-facing or be narrowed when the
backlog is next edited: source-side outgoing threat is only relevant to an
enemy-versus-enemy consumer if that consumer models a living recipient creature
with a threat list and a real target relationship. At that point, threat goes
on the recipient and the holder gate applies there. Do not model it by
inverting signs, mutating the attacker mob's table, or treating a playable
party build as an ordinary unowned creature.
No runtime code, catalog, or backlog file was changed for this audit.
+53
View File
@@ -0,0 +1,53 @@
# Legacy Boss Pacing Fix — 2026-10-03
## Change
The existing 25-second ordinary-boss and 45-second final-boss minimums now hold for the measured legacy cohorts without changing those assertions or reducing encounter timing thresholds.
The Stockades WoW starter health anchors are now 1,800 at enemy level 2 and 2,600 at enemy level 4. Those replace 1,050 and 1,500, respectively. At level 1, the measured Priest plus four Ready companions now clear the ordinary and final bosses in 25.3 and 45.7 seconds. At level 3, they clear in 25.6 and 48.1 seconds.
The compatibility retune documented here uses a separate player-level multiplier only when `characterSource === "rom"` and `statRuleset === "wow"`: 1.0 through level 7, 1.12 at level 8 through 70, then a linear increase to 2.3 at level 80. This applies to boss health floors only. This compatibility retune did not change trash health, the native RoM health bands, native damage-budget bands, enemy damage, loot, cap 80, actor mode defaults, or Ready policy.
## Why the RoM compatibility branch stays separate
The pacing harness calls `dungeonEnemyScaling` for RoM parties without passing `statRuleset`, so it intentionally exercises the legacy `wow` ruleset default for those RoM characters. Generated RoM NPCs still use their native snapshots by default. This is a supported mixed-mode cohort; the harness calls and actor mode defaults remain unchanged.
The compatibility multiplier is gated on that existing legacy `statRuleset: "wow"` path. At the time of this compatibility retune, native-mode RoM boss health remained exactly 8,330.293333 at player level 8 and 1,312,656 at level 80 for the Stockades regression fixture; `nativeDamageBudgetScale` remained 1 and 40. A later, independently measured native level-one boss calibration changes the interpolated level-8 value to 7,983.197778 while preserving the level-80 value and both damage-budget values. See [the native level-one boss pacing addendum](ROM_NATIVE_LEVEL_ONE_BOSS_PACING_2026-10-03.md). The compatibility retune did not edit either native table; the later calibration changes only the level-1 boss-health anchor and leaves `ROM_NATIVE_DAMAGE_BANDS` untouched.
The equipment completion added optional off-hand and bow damage/speed/range values to native NPC snapshots. Those snapshot fields are available to future consumers; they do not make the shared enemy action scheduler emit additional off-hand or bow swings, and they do not automatically increase its shared enemy damage budget. This pacing change does not add extra enemy attacks or claim that the live swing path consumes those channels.
## Before and after evidence
The untouched baseline was captured with `BOSS_BALANCE_REPORT=1` and `NODE_OPTIONS=--max-old-space-size=8192` before retuning. Its 65 samples are archived at `artifacts/rom-enemy-followup/before-compatibility-pacing.json`. The test suite stopped at the first failing assertion within each affected test, so the baseline has only the first seed for the failures below.
| Cohort and level | Before ordinary / final (health) | After ordinary / final (health) |
| --- | --- | --- |
| WoW Stockades, level 1 | 14.6s / 27.1s (1,050 / 1,995) | 25.3s / 45.7s (1,800 / 3,420) |
| WoW Stockades, level 3 | 15.1s / 28.6s (1,500 / 2,850) | 25.6s / 48.1s (2,600 / 4,940) |
| RoM damage Mage, level 8 | 23.6s / 46.3s (15,619 / 29,677) | 26.8s / 52.9s (17,494 / 33,238) |
| RoM party, level 80 | 11.3s / 23.6s (273,470 / 519,593) | 27.1–28.1s / 53.3–57.1s (628,981 / 1,195,064) |
After retuning, the report contains 83 samples: all three WoW seeds at levels 1, 3, 8, 20, 40, and 80; all five damage-Mage levels; and all 12 standard RoM party seeds at levels 1, 8, 20, 40, and 80. The complete report is archived at `artifacts/rom-enemy-followup/after-compatibility-pacing.json`.
Across the post-change samples, ordinary/final clear-time ranges were:
| Cohort | Level | Ordinary boss | Final boss |
| --- | ---: | ---: | ---: |
| WoW party | 1 | 25.3s | 45.7s |
| WoW party | 3 | 25.6s | 48.1s |
| WoW party | 8 | 33.1s | 61.0s |
| WoW party | 20 | 48.1–49.0s | 93.8–97.0s |
| WoW party | 40 | 40.8–45.4s | 78.4–81.3s |
| WoW party | 80 | 95.3–100.1s | 191.7–193.7s |
| RoM damage Mage | 1 | 42.1s | 109.3s |
| RoM damage Mage | 8 | 26.8s | 52.9s |
| RoM damage Mage | 20 | 30.1s | 62.6s |
| RoM damage Mage | 40 | 35.1s | 69.1s |
| RoM damage Mage | 80 | 27.1s | 57.1s |
| RoM party | 1 | 81.1–92.5s | 191.2–199.4s |
| RoM party | 8 | 41.2–42.6s | 103.7–106.9s |
| RoM party | 20 | 36.6–40.3s | 73.6–75.1s |
| RoM party | 40 | 38.1–42.1s | 78.1–79.6s |
| RoM party | 80 | 27.1–28.1s | 53.3–57.1s |
The full `dungeonBossScaling.test.ts` suite passed all 18 tests. The additional focused regressions passed all 6 tests across `romNativeDungeonPacing.test.ts` and `biteSizedBossBalance.test.ts`. The real-mechanics Priest test also passed its boss-attack, incoming-damage, healing, and survival assertions; its helper does not add that run to the timing report.
@@ -0,0 +1,35 @@
# Lichborne control escape — 2026-10-06
## Source proof
Lichborne spell 49039 is an exact WoW 3.3.5a source row, not a tooltip-based inference. The selected generated row is `wow335-death-knight-lichborne`, class `death-knight`, source profile `wow335`, talent node `talent-2215`, learned at level 55. It is a self spell with a 10-second duration, zero cast time, zero GCD, 120-second cooldown, and no power cost. Its spell defense fields are `damageClass=0`, `schoolMask=32`, `directDamageFromEffects=false`, and the complete retained attribute words are `Attributes0=262144`, `Attributes1=163872`, `Attributes3=0`, `Attributes5=393224`.
The local client profile is World of Warcraft build `3.3.5a.12340`, read from `../wow335a/Data/enUS/patch-enUS.MPQ`, table `DBFilesClient/Spell.dbc`. The source-audit artifact at `artifacts/enemy-control-followup-2026-10-06/source-audit.json` records the raw `Spell.dbc` row. Its eight raw attribute words, in order, are `[262144, 163872, 0, 0, 0, 393224, 0, 0]` (`0x00040000`, `0x00028020`, then three zero words, `0x00060008`, then two zero words). The active generated source remains `src/game/wow335AbilityData.generated.json`.
The selected row has exactly three effects. Each is effect type 6 (`APPLY_AURA`) and aura type 77 (`MECHANIC_IMMUNITY`), with caster recipient and zero points-per-level. The raw `Spell.dbc` base-points are zero for all three; the selected generator represents them as base points 1 and preserves `sourceBasePoints=0`.
| Effect | Raw misc value | Mechanic | Raw base points | Die sides | Selected source base points |
| --- | ---: | --- | ---: | ---: | ---: |
| 0 | 1 | Charm | 0 | 1 | 0 |
| 1 | 5 | Fear | 0 | 0 | 0 |
| 2 | 10 | Sleep | 0 | 0 | 0 |
`Attributes1=163872` is `0x00028020`; it includes `SPELL_ATTR1_IMMUNITY_PURGES_EFFECT=0x00008000`. `Attributes5=393224` is `0x00060008`; it includes `SPELL_ATTR5_ALLOW_WHILE_STUNNED=0x00000008`, `SPELL_ATTR5_ALLOW_WHILE_FLEEING=0x00020000`, and `SPELL_ATTR5_ALLOW_WHILE_CONFUSED=0x00040000`. The source row therefore proves Charm, Fear, and Sleep immunity and purge, plus casting while stunned, feared, or confused. Its cast allowances are separate from the mechanics it grants: Lichborne does not grant Stun or Confuse immunity.
The existing generated aura mapping represents the selected Fear and Sleep effects as control immunities. The current `AuraDefinition` control-immunity type has no Charm value, so the source proof records Charm from the exact DBC effect but does not alias it to a different runtime mechanic.
## Pinned core behavior
The read-only AzerothCore reference is pinned to `e822d718322289dd036fb2daf8867ba41283bf9a`. In `src/server/shared/SharedDefines.h`, the attribute definitions name the purge, stunned, fleeing, and confused flags above. In `src/server/game/Spells/SpellInfo.cpp:2488–2537`, `SpellInfo::ApplyAllSpellImmunitiesTo` applies each mechanic-immunity mask and, when the purge flag is present, removes existing auras whose spell mechanic masks intersect it. Lichborne therefore purges matching Charm, Fear, and Sleep mechanics when applied; its source effects do not include Stun or Confuse, so a separate Stun or Confuse aura stays active.
In `src/server/game/Spells/Spell.cpp:6836–6853`, `Spell::CheckCasterAuras` derives the cast-time mechanic mask from immunity effects on spells carrying the purge flag. The later active-aura check skips an aura whose whole spell mechanic mask intersects that immunity mask (`Spell.cpp:6920–6978`). The `Attributes5` allowances independently cover stunned, fleeing, and confused caster states. This explains both shared shout cases: 49039 can start while feared, and it can start while the 20511 child applies a stun effect because that aura retains spell-level `Mechanic=FEAR`. A standalone stun also permits casting through the explicit stunned flag, but remains active after the cast. Confusion likewise permits casting and remains active.
## Runtime boundary
`enemyControlImmunityPurge.ts` recognizes only the exact selected WoW rows for Berserker Rage 18499, Bladestorm 46924, and Lichborne 49039. For Lichborne it checks the class, ability identity, source profile, damage class, school mask, all retained attribute words, and each aura's effect index, aura type, mechanic value, base-points scalar, die sides, points-per-level, recipient, and generated source aura ID. Missing or changed fields fail closed.
The Lichborne proof grants `charm`, `fear`, and `sleep`, records the named-shout Fear purge, and separately records the direct cast allowances `fear`, `stun`, and `confuse`. The named cleanup remains limited to active, same-target auras from spells 5246, 19134, 20511, and 29544. It removes those because their complete spell-level mechanic is Fear, including the 20511 aura that applies a stun effect. A recognized generic Fear, stun, or confusion label can also allow Lichborne to be cast through its explicit `Attributes5` flags; those auras remain active and keep their control state. Berserker Rage remains limited to its named-shout Fear purge and blocked by separate stun, confusion, and generic Fear; Bladestorm remains unable to start through control despite its later Fear and Stun immunity aura. Unknown source-spell controls fail closed.
Player and party integration must select the learned Lichborne row before using this proof. That integration retains the existing target validity, cooldown, global cooldown, and cost checks. No generic magic miss, resist, or deflect roll is part of this proof.
Focused helper validation: `npm test -- --run src/game/enemyControlImmunityPurge.test.ts`.
@@ -0,0 +1,21 @@
# Mechanics backlog follow-up — 2026-10-02
This follow-up corrects and supersedes selected first-pass findings in [the initial run report](MECHANICS_BACKLOG_RUN_2026-10-02.md). It records current source/runtime status after the separate class-mechanics workers completed their bounded changes. It is not an all-class or balance certification.
## Current catalog inventory
The generated RuneWaker catalog contains **932 skills**: 590 active and 342 passive, with 937 rank rows. All 932 generated rows have resolved icon sources. Runtime composes 936 ability definitions (the 932 generated rows plus four separately composed definitions) and 937 ranked versions, for 1,873 definition/rank entries. These counts are asserted by `src/game/romPlayerCatalog.test.ts` and the generated snapshot at `src/game/romPlayerCatalog.generated.json`. The older 929-row class coverage table is historical.
## Resolved implementation updates
- **WoW Hunter pets:** Cat is now a selectable, persisted player-pet profile alongside Wolf and Turtle. The local Cat kit has Claw, Rake, and Prowl; Rake keeps its direct physical packet separate from its armor-ignoring bleed, and Prowl's one-charge damage bonus applies to a ready melee auto before spell autocasts. Generated Hunter companions remain Wolf. Other family abilities, pet care/training, and owner critical-stat inheritance remain open. See [the family note](WOW_HUNTER_PET_FAMILIES.md).
- **RoM Knight:** Divine Punishment 491608 uses current CoA's 28.5% Punishment bonus and 2% general damage-taken increase per pre-spend Holy Seal for 10 seconds. God's Vengeance 499934 uses the separately learned Knight/Rogue child Punishment 499909; at exactly four of its own target's Seals, a landed hit resets only the caster's learned Shadow Step. Panther's Blessing 493047 restores 10% max HP and 1% max MP on a resolved dodge. The percentage pools and whole-point rounding are explicit simulator interpretations because CoA does not define the bases or rounding. The legacy RuneWaker +2 Dodge child remains suppressed. See [the Knight source audit](ROM_KNIGHT_REMAINING_REFERENCES_AUDIT.md) and [Panther runtime note](ROM_KNIGHT_PANTHER_DODGE_PROC_2026-10-02.md).
- **RoM Champion:** Rank-2 Forge 498604 is the level-22 upgrade of Forge 498523 through Chain Drive 498535. Its normal-attack trigger preserves group order: Forge stack and Rage resolve even if the later effect roll fails; group 1 uses an 80% exact Shield Form buff check, then a 30% fallback, with the target resolved once. The eight-second effect resets Rune Pulse through its effect-use callback. Rune Pulse 498529 grants +20% outgoing physical and magical damage for one second at cast acceptance, so it expires before the two-second impact; it does not boost that impact. Dark Energy Strike 498599 resolves physical then Shadow packets; a surviving positive physical result gates one 15% cast-level reset of the owner's Rune Siphon, regardless of the later Shadow packet's result. Rank-1 Forge companion auto-attacks now emit owner/expiry-qualified roll eligibility; fully absorbed swings do not proc, while a landed normal swing grants its own stack and +16 Rage total (+10 Forge, +6 normal attack). Focused Forge, Champion, and party-runtime tests passed 74 tests across three files. The next-Curse transform, Shield Form's complete child behavior, and Rune Overload target selection also remain unresolved. See the [Champion source follow-up](ROM_CHAMPION_SOURCE_FOLLOWUP_2026-10-02.md) and [Dark Energy runtime note](ROM_CHAMPION_DARK_ENERGY_STRIKE_RUNTIME_2026-10-02.md).
- **RoM Druid source-only findings:** Revival Slash 499496's hidden child has a 25% roll after the original target survives the physical group; it runs once per surviving cast. Its reduced hidden HolyHeal/HoT is not a complete runtime formula. Spring Flower Eulogy's learned child 499935 has a bound 30% +1 Nature Power group and source-defined six-second stack/expiry chain, including 1/3/5% max-HP timeout heals. The periodic tick formula still needs final native healing values. Learned Inspiration Display child 499942 has an ordered, 60%-gated first effect and 30% fallback, plus the 10-second timeout modifier; this proves the learned variant's acquisition path, not an automatic trigger from public Inspiration or Spiritual Gush. Quick Light Protection, Boiling Rock, local Avalanche, and Extended Recovery's Nature Power chance remain without usable local numeric triggers. Verified base MND maps to Wisdom, but no final effective MND, MDMG, Magic Power/MPow, HealPowerRate, HealPoint, and target-heal-absorption bindings were established. See the [Druid source follow-up](ROM_DRUID_SOURCE_FOLLOWUP_2026-10-02.md); these source findings alone do not claim complete playable heals.
- **RoM Warlock:** local RuneWaker Mind Shield 498648 guarantees a Ring of Comfort reset after a landed Urgent Heal when learned; current CoA still leaves its separate chance unquantified, so this local rule is not imported. Local learned 499869 is level-70 Warlock/Warrior Mind Transference (key 546844, prerequisite 499868, slot 25), converting Rage to Soul Points and applying its EndUseLua addition/suppression; it is not current-CoA Psychic Warrior or Enraged. Local End of Thought 498699 is Warlock/Rogue and has a pre-hit <=35%-HP callback that applies a four-second buff, but its one-second child has no located native timed-magic consumer. Breathing Control 498634 and Deep Breathing Control 499870 still have no local trigger contract. These source findings do not complete the current-CoA Psychic Warrior damage path, Mind Shield chance/Defense Net amount, End of Thought current-version contract, or Breathing riders. See the [Warlock source follow-up](ROM_WARLOCK_SOURCE_FOLLOWUP_2026-10-02.md) and [current-CoA conflicts audit](ROM_WARLOCK_REMAINING_CONFLICTS_AUDIT.md).
## Verification and current limits
The aggregate focused run passed **382 tests across 35 files**, with four existing IndexedDB skips. Ready-five passed 7 Vitest tests and 20 Python tests. After the narrow Hunter summon-card CSS correction, the fresh 8 GB TypeScript/Vite production build, prebuild asset audits, and release-bundle verification passed. The earlier four baseline assertions and the current catalog/count assertions now pass; the earlier 202-test/20-file run and 63-path release check in the initial report remain historical results, not the latest totals.
Final Cat UI QA passed, including a replay against the exact final production build. Native pet/reaction selectors, mouse Stay/Follow controls, Growl, and the real-combat change lock responded. The Cat selector persisted across reload while a second character remained Wolf. In the final narrow screenshot, the party row ended at y=269 and the selector card occupied y=306–420, leaving a 37-pixel gap; there was no top-right HUD overlap or horizontal overflow, and the loaded canvas was visible. Escape opened pause, Spellbook opened, the actual Call Pet entry was clicked, and the overlay closed with the existing Cat still selected; this verifies that activation route, not summoning after the pet is absent. Revive remains untested because the pet never died. No live Rake/Prowl cast or Cat model appearance has been verified. There were no page or HTTP errors; the only console message was a favicon 404. The rank-1 Forge companion event correction is implemented; focused Forge, Champion, and party-runtime tests passed 74 tests across three files. Ready-five passed 7 Vitest and 20 Python tests after the correction. The 382/35 aggregate with four existing skips is the earlier passing selection, and the 74-test selection overlaps it; do not add the totals. The final post-fix 8 GB TypeScript/Vite production build passed with prebuild asset audits and bundle verification; Vite processed 1,260 modules in 11.58 seconds. `npm run release:check` passed across 94 changed paths, including untracked files. The full repository test suite and all-class balance sweeps were not run.
+43
View File
@@ -0,0 +1,43 @@
# Mechanics backlog reconciliation — 2026-10-02
This run reconciles new source and runtime work into the active class backlog and audit. A generated-catalog omission does not establish source absence: inspect the raw RuneWaker records, linked Lua/engine paths, learn rows, and event consumers where they are available. Local RuneWaker and current Chronicles of Arcadia behavior remain version-qualified, and missing amounts or event semantics stay open. The Ready certification set is unchanged. All subprocess work used GPT-6 Luna at xhigh; no higher-tier subprocess model was used.
## Implemented or source-reconciled slices
| Mechanic | Current status | Scope and limit |
|---|---|---|
| WoW Hunter pet families | Partial player-profile slice implemented. | Extracted 40 family rows; pinned-core classification identifies 32 Hunter families. Player selection/persistence supports Wolf and Turtle; Call/Revive preserves the selection, and encounter changes are locked. Turtle's Shell Shield 26064 is modeled; its engaged autocast is simulator policy. Generated companions remain Wolf. Full family ability coverage, stable/feed/happiness, training, and critical inheritance remain open. See [family runtime audit](WOW_HUNTER_PET_FAMILIES.md). |
| WoW Death Knight Wandering Plague | Implemented for player and generated-companion Death Knights. | Positive Blood Plague/Frost Fever ticks use generated 33/66/100% tick-damage ranks and owner melee-critical chance. One-second owner cooldown is AzerothCore corroboration. Triggered splashes cannot recurse and skip active break-on-damage statuses. See [source/runtime note](WOW_DEATH_KNIGHT_WANDERING_PLAGUE.md). |
| WoW Shaman Nature's Guardian | Implemented for player and generated-companion Shamans, except the unknown self-heal. | Generated 33/66/100% chance on a landed positive nonperiodic hit crossing from at/above 30% to below 30%; actor-owned 30-second cooldown; one guaranteed critical for the next resolved Nature damage or healing spell. Self-heal amount/formula remains unwired. See [event model](WOW_SHAMAN_NATURES_GUARDIAN.md). |
| RoM Scout paired passive markers | Implemented for three exact pairs. | Wind Return 499548, Revival Engraving 499552, and Forest Guidance 499575 stay learned markers; translated child effects no longer appear on the passive owner. Their absent trigger rows and unsupported companion/pet target behavior remain open. See [source audit](ROM_SCOUT_REMAINING_PASSIVES_AUDIT.md). |
| RoM Priest/Champion Protection Rune Seal | Implemented for player and generated-companion owners. | Positive periodic Regenerate 490269 heals may use local 8% chance to reset only that actor's learned Heart Rune Energy 498612 cooldown. CoA gives only “slight chance,” so 8% is a local fallback. A possible healing-strength rider remains unsourced. See [source/runtime audit](ROM_PRIEST_REMAINING_PASSIVES_AUDIT.md). |
| RoM Knight/Rogue Panther's Blessing | Unsupported passive output suppressed. | 493047 remains a learned marker; local +2 Dodge child has no proc chance or shield-state handler. Current CoA reuses the ID for a different skill, so no cross-version mechanic is mapped. See [trigger audit](ROM_KNIGHT_REMAINING_REFERENCES_AUDIT.md). |
| RoM Champion Shield Form | Learnability question resolved; runtime still open. | Local `learnmagic.db` has Champion-primary 498562 at level 16 behind Dwarf flag 546211 and quest progression. The level-derived catalog omits flag-gated acquisition; its toggle and child effects remain unimplemented. Other Champion proc gaps remain open. See [source audit](ROM_CHAMPION_REMAINING_MECHANICS_AUDIT.md). |
| RoM Warrior/Druid Rage of Calmness | Quantified Whirlwind clauses stay implemented; the post-hit general Rage discount stays unwired. | Local 494377 supplies −10 Rage and −10 seconds for local Whirlwind 490133; component 506368 supplies a 20-second post-hit window but no discount amount. Current CoA Whirlwind 494939 separately says 30%/15 seconds/20-second retrigger lockout, without linking that rider to passive 494377. Do not transfer 30%. See [bounded source audit](ROM_WARRIOR_RAGE_OF_CALMNESS_SOURCE_AUDIT.md). |
| RoM Warden Revival | Source-backed 499544→623079→499545 chain and 499542 heal integrated for player and generated-companion Rogue/Wardens. | Learned 499544 arms an actor-owned 900-second state. Only normal noncritical hits with positive post-absorb HP loss and a living owner add that actor's 623072 charge (15 seconds, max ten) and apply component 623527's six-second +20 physical-dodge-rate points. Revival heals `maxHP × (10 + 5 × charges)%` as normal/noncritical FixPer. `damagePlayer` lacks an outcome payload, so that adapter treats positive post-absorb loss as normal. See [state-chain source audit](ROM_WARDEN_REVIVAL_STATE_AUDIT.md). |
## Source and runtime blockers kept open
| Area | Finding |
|---|---|
| RoM Mage/Warden Flame Follower | Local 494051's tooltip states a one-second Fireball cooldown reduction and increased critical rate, but raw records have no linked effect, trigger phase, or critical amount. Current CoA 490244 is a later active-summon revision; reused 494051 is Purgatory Fire. Do not map these to the old RuneWaker passive. See [raw source/runtime audit](ROM_MAGE_FLAME_FOLLOWER_RUNTIME_AUDIT.md). |
| RoM Druid conditional passives | Keep source versions and event gaps distinct. Revival Slash has a linked reduced Recover child, but chance/roll semantics are absent; Quick Light Protection has no bound local hook and current CoA reuses the ID; Boiling Rock has no linked proc; level-70 Inspiration Display's bound child is deterministic +1 Nature's Power and does not implement its separate Inspiration/double-effect chance; local Avalanche remains open. Current CoA Avalanche 494029 publishes 18.8% generic defenses only at skill +105, without a lower-rank curve, defense school, or Nature's Power rider; CoA Rockslide 494063 differs from local 493543, with a two-second first hit and unspecified extra-hit timing. Extended Recovery's local +6 seconds is implemented but its Nature's Power chance remains open; Spring Flower Eulogy's separate Nature's Power chance/expiration heal is not linked in the local raw graph. Faction conversion and Rebirth debt/item behavior remain helper-only until combat models reputation, faction, debt, and item use. See [source audit](ROM_DRUID_REMAINING_PROC_AUDIT.md). |
| RoM Warlock | Completed Mind Transference 498642, Divine Assistance 498668, and caster-scoped +1 Psi on Ring of Comfort 498641 / Mind Shield 498648 stay closed. Remaining distinct gaps are Breathing Control proc chance/event phase/extra Focus, Deep Breathing Control's 15% HP trigger and extra Focus amount, Mind Shield's Ring reset chance/Defense Net increase, Psychic Warrior hybrid mitigation and extra-hit semantics plus unquantified attribute riders, hidden child 499869 identity, and End of Thought's tick interval. WoW Soul Leech 1678 stays only in the WoW section. See [source audit](ROM_WARLOCK_REMAINING_CONFLICTS_AUDIT.md). |
| WoW Paladin Vindication | Rank-3 attack-power gain stays unwired because the DUMMY effects do not identify an AP operation or child. Its rank chance and AP-reduction child are separate implemented behavior. |
| RoM Scout Enhanced Throat Attack | Extra range stays open: local passive `range` is cast distance, not a bonus. Current CoA rework does not fill the RuneWaker value. |
| RoM Rogue ammunition | Player ammo inventory/consumption remains unmodeled. |
| RoM Warden Revival native riders | HolyHeal 620302 and type-200 magical dodge remain unwired because the simulator lacks native MND/MPow/heal-rate inputs and a separate magical-dodge consumer. Do not synthesize neutral-stat healing rates or merge type-200 into physical Dodge. See [state-chain source audit](ROM_WARDEN_REVIVAL_STATE_AUDIT.md). |
## Validation and limits
The Ready-five check passed 7 Vitest and 20 Python tests. The final combined focused run passed 202 tests across 20 files with 4 IndexedDB skips. The separate Warden focused state-chain run passed 77 tests, and the exact 499544 catalog assertion passed in its filtered check; these selections overlap the combined run, so totals must not be added. The 8 GB TypeScript check and final full `npm run build` passed after the Revival state chain and final narrow Hunter placement edit; prebuild asset audits and release-bundle verification passed. The final `npm run release:check` passed on 63 changed paths, including untracked files.
Final fresh-dist Hunter UI QA passed. In the loaded scene at 390×844, the selector card spans y=306–420, clears the party row ending at y=269 by 37px, and does not overlap the top-right HUD. The selector is disabled while real Wailing Caverns enemies are engaged; after the encounter ended naturally, the rendered control selected Turtle, the profile showed Shell Shield 26064 and no Furious Howl, and reload retained Turtle while the other character retained Wolf. No page or network errors occurred except a favicon 404; there was no horizontal overflow. The UI-created Marksmanship characters were raised to level 10 through the progression control for this mechanics diagnostic; this is not Ready-party or balance certification. Escape/Spellbook Call/Revive remain visually unverified. See the scoped evidence in `playtest-artifacts/hunter-families/` and `PLAYTEST_NOTES.md`.
Four unrelated assertions were reproduced on clean baseline `b16821e9`: Knight Divine Punishment expected 2 entries but got 1, Knight God's Vengeance expected its deterministic proc but got none, the Mage/Druid elite milestone sequence expected 15/20/25/30… but got 15/20/25/25…, and Druid/Rogue Speed Catalysis expected 15 Energy but got none. These baseline failures are not attributed to this reconciliation. The full test suite and all-class balance sweeps were not run. Historical class blockers remain open; this reconciliation is not an all-clear.
## Later correction and current status
The counts, 202-test/20-file focused run, 63-path release check, and four reproduced assertions above are the first-pass history, not the latest status. The current generated catalog has 932 skills (590 active, 342 passive) and 937 ranks; runtime composition has 936 definitions plus 937 ranked versions. The four baseline assertions and catalog/count assertions now pass.
The later aggregate passed 382 focused tests across 35 files with four existing IndexedDB skips, and Ready-five passed 7 Vitest plus 20 Python tests. The full 8 GB production build and bundle checks passed after the Cat summon-card CSS correction, and Cat UI QA passed with its remaining visual limits recorded in the current report. The later rank-1 Forge companion event correction now emits owner/expiry-qualified auto-attack eligibility; focused Forge, Champion, and party-runtime regressions passed 74 tests across three files, and Ready-five passed again after the fix. The final post-fix 8 GB TypeScript/Vite build passed with prebuild asset audits and bundle verification; exact-final-dist Cat QA replay also passed. `npm run release:check` passed for 94 changed paths, including untracked files. See [the current follow-up](MECHANICS_BACKLOG_FOLLOWUP_2026-10-02.md) for corrected mechanics, source links, and active limits.
@@ -0,0 +1,80 @@
# Mechanic parity and campaign boss pass - 2026-10-04
> **Current QA policy (2026-10-05):** Routine live tests use Stormwind Stockade: Cellblock Rush (`bite-sized-stormwind-stockade`); record the boss selected from the run ID. Full-source Stockade campaigns require explicit route selection. The Wailing captures and commands in this dated report remain historical; follow [the current test policy](TEST_DUNGEON_POLICY.md) and root `AGENTS.md`. A new Wailing reproduction needs an explicit owner request.
## Outcome
Timed player/NPC Killing Spree and source-confirmed active-five RoM fixes are implemented. Vow's live counter and full 8.4-second silence pass after correcting the source Nature Thorns cast gate. Normal Barren fully clears in 13:36.9 with one casualty; strict Wailing reaches and defeats Lady with all five actors alive, while full Wailing completion remains unverified. Sampled camera visibility/right-drag checks pass. The final build, 296 focused assertions, Ready-five checks and repository/vault hygiene pass. Blood Arrow's separate base toggle/cost migration remains open.
## Authorized scope
Complete Killing Spree's timed player/owned-NPC mechanism; verify Vow of Silence in an actual Lady Anacondra fight; extend normal Barren Caves and Wailing Caverns routes to bosses and attempt full clears; audit and implement source-confirmed gaps for the five active native RoM identities. Independent work runs through GPT-6 Luna with extra-high reasoning.
The native set is Knight/Scout tank, Priest/Knight healer, Rogue/Warrior damage, Scout/Rogue damage, and Mage/Warlock damage. This is a targeted diagnostic and implementation pass, not an all-class balance sweep or a readiness promotion. The five WoW Ready builds retain the routine certification scope.
Level cap 80, automatic Training gear, saved-profile stat compatibility and loot scope are preserved. No commit, deployment or live-report status mutation is included. Existing shared-workspace changes are preserved.
## Evidence ownership
- `docs/WOW_KILLING_SPREE_PARITY_2026-10-04.md`: source-timed player/NPC mechanism, cleanup and focused tests.
- `docs/ROM_FIVE_MECHANIC_GAPS_2026-10-04.md`: exact active identities, confirmed fixes and unresolved source/runtime contracts.
- `docs/ROM_CAMPAIGN_BOSS_PASS_2026-10-04.md`: normal campaign traversal, boss/full-clear attempts, live Vow evidence and screenshots.
- `docs/ROM_BARREN_FINAL_CLEAR_2026-10-04.md`: independent final-build normal Barren rerun.
- `docs/ROM_VOW_LIVE_FINAL_2026-10-04.md`: independent final-build ordinary Boss Testing Lady/Vow fight, separate from campaign completion.
- `docs/ENEMY_SILENCE_CAST_GATE_2026-10-04.md`: source-confirmed Thorns silence-selection correction discovered during the full live observation window.
## Validation boundaries
Exploratory current-dist captures are labeled separately from final-build checks. Normal campaign movement and casting use ordinary inputs; staged casts, teleports and edited combat state cannot establish live-route proof. Browser screenshots require visual inspection. A completed harness recording does not establish a successful clear, survivor count or counter cancellation without matching telemetry.
## Camera implementation
Normal Wailing traversal reproduced a foreground pillar obscuring the player and companions while HTML labels remained visible (`playtest-artifacts/native-routes/baseline-20261004-134537874/wailing-caverns-segment-end.png`). The player follow camera queried physical terrain only; the spectator follow camera already included the dedicated visible wall/pillar layer. `src/scene/dungeonCameraObstruction.ts` now shares that combined query, preserving the physical sphere sweep, actor exclusion and immediate pull-in/eased pull-out behavior. Sight-only sensor proxies now shorten the player boom as well.
Real Rapier obstruction tests plus existing line-of-sight and input tests pass 41 assertions across four files. Final-build live camera/route evidence is recorded in the campaign report; this static result alone does not certify every cave viewpoint.
## Mechanic implementation
Killing Spree now executes five scheduled owner-local assaults through the two-second window for players and generated Rogue companions. The learned companion action enters its existing Combat rotation; damage/aura ordering, retained targets, actual scene relocation and death/reset/roster-removal cleanup have focused coverage (71 tests). Seeded target choice and estimated weapon-child/teleport details remain simulator approximations.
The active-five audit corrects Knight/Scout Blood Punishment to +15% received healing and +5% Holy damage on the live Blood Arrow aura. Actual companion casts exposed and corrected presentation-derived RoM combat schools and missing outgoing aura handling on the compatibility no-roll direct path; native roll-based damage must not apply those modifiers twice. The audit retains unresolved source values and the separate Blood Arrow base-toggle/cost migration explicitly.
Routine Ready-five certification passes seven game and twenty Python tests. Final production build and browser evidence are required separately below.
## Campaign build and integration checks
- Focused suites: 71 Killing Spree/runtime/registry, 154 active-five pair/integration, and 41 camera/line-of-sight/input assertions pass (266 total across eleven files).
- Ready-five: seven game assertions and twenty Python tests pass. No all-class balance sweep or readiness promotion.
- `npm run build` passes application/project TypeScript, Vite, prebuild texture/performance audits, postbuild compression and release-bundle verification. The existing prebuild loot-catalog generation runs unchanged; this task adds no loot wiring.
- Campaign assets: `index-DHQInfBp.js`, `combatStore-Cx06rFzG.js`, `GameRuntime-D87YWi4Q.js`, `PartyFrames-5jlxKxxK.js`, `romAbilityCatalog-CHjYfHkT.js`, `index-499eecpe.css`.
- Recorded browser scope: independent normal campaign Barren/Wailing attempts and a separate ordinary Boss Testing Lady/Vow fight. The later silence-correction replay identifies its rebuilt assets below; failed exploration is retained separately.
## Verified live outcomes
Barren Caves clears through normal campaign movement and combat on the final asset set. The native result overlay reads **FULL DUNGEON CLEAR**, Anglo defeated 1/1, at **13:36.9**; the boss record independently shows dead with zero HP. The initial level-30 Priest/Knight naturally finishes at level 36. Rorik dies; the player, Caelan, Durnik and Veyra survive (four of five actors). Effective healing totals 46,328.47. This establishes one full clear, not a death-free balance certification. Maximum sampled player-to-living-companion distance is 12.52 m during the route and 15.56 m in post-pack snapshots. No loot action was taken. See the independent Barren report and `playtest-artifacts/campaign-boss-pass/final-build-20261004-150021873/`.
The initial independent ordinary Boss Testing Lady fight confirms Vow cancels a real source Lightning Bolt (9532), without staging the cast or changing combat state. Before Vow, source creature 3671 has an interruptible Nature bolt and only Fear/Horror mechanic immunities. The completed Vow event targets Lady; immediately afterward the cast is null and her actual Silence status lasts 8,400 ms. The aura applies before the explicit interrupt effect, so it cancels the cast before that effect can set a Nature school lock. A zero school-lock value is not failure when the silence and cast cancellation are verified. Before/after screenshots show the bolt bar disappear; no presentation-event capture is claimed. The fight defeats Lady with all five actors alive and no XP/loot. Evidence: `playtest-artifacts/vow-live-final/final-build-20261004-151254152/`; the scoped report distinguishes the original harness false-negative from successful cancellation. Longer observation in `final-build-20261004-151736260/` finds Nature Thorns starting during silence, leading to the enemy selector correction and successful rebuilt replay below.
Normal Wailing movement has revisited the vicinity of the previously clipped view on the final build. The screenshot triplet shows loaded bodies and equipped silhouettes, right-drag rotation, and a stable released view. The foreground rock that obscured the earlier sampled view is absent in this nearby pose. The campaign report records the exact pose/input telemetry and final route outcome; this is a sampled camera improvement, not universal cave visibility certification.
Wailing's strict route reaches Lady's authored anchor without the earlier fall: 433.96 m actual travel against 432.42 m guidance, all 284 checked movement vertices reached, no route block and five actors surviving. Effective healing totals 28,587.81. Lady engages and is defeated during ordinary pack stabilization before the endpoint. Real source Lightning Bolt damage, repeated player Rising Tide casts, a final clipped companion hit and the captured feedback **That target is already defeated** establish the fight/defeat. The original endpoint-only `boss-not-reached-or-not-loaded` classifier misses this natural midroute fight after the boss leaves active state; it is not evidence of a spawn defect. The run does not defeat the other seven required bosses or complete the Naralex/Mutanus event, so **full Wailing clear remains unverified**. Empty guard-attempt records do not prove those living packs cleared. Evidence: `playtest-artifacts/campaign-boss-pass/final-build-20261004-151549020/`.
The Wailing camera probes rotate yaw by -0.378 radians while right mouse is held, with `document.pointerLockElement` null. After release, an unheld pointer move changes yaw by zero. Player displacement during either drag is less than 0.001 m. The earlier clipped-position probe is 5.18 m from that old pose; the improvement is a nearby sample, not an exact-position comparison or a measured rendered-camera boom extraction. Character bodies and staff/bow/shield silhouettes were visually inspected at route checkpoints and both probe triplets.
## Silence correction and final replay
The full live observation exposes the actual pinned Thorns 8148 row: Nature school, self aura, `delivery: melee`, and no explicit damage class/kind. The old new-cast selector inferred melee from delivery and let it start during silence; active-cast cleanup then canceled it on the next advance, producing repeated starts without resolution. Enemy selection now checks nonphysical school **or** explicit spell kind for silence eligibility. Physical melee/ranged remain available and the damage-roll classifier is unchanged. The imported attack contract has no prevention-type field, so this remains the simulator's explicit school/kind control policy. The separate source report and actual-source regressions cover repeated silence advances, expiry and resumed Thorns release. A coordinated rebuild and independent live replay follow this correction; the earlier campaign/camera evidence retains its recorded asset identities.
After the correction, `npx vitest run src/game/enemyCasting.test.ts src/game/romPriestChampionRuntime.test.ts src/game/wailingCavernsParity.test.ts` passes 30/30. The combined scoped validation is **296 assertions across fourteen files** (266 mechanic/camera assertions plus these thirty); Ready-five is rechecked at seven game/twenty Python passes. The final `npm run build` passes project TypeScript, Vite, pre/post audits, compression and bundle verification. Corrected assets are `index-Cm7Olrd2.js`, `combatStore-1B4KOVhS.js`, `GameRuntime-hM1AaOYR.js`, `PartyFrames-BfZEkXH5.js`, `romAbilityCatalog-DjRUCJbs.js`, and `index-499eecpe.css`. The independent Vow replay uses this corrected set; the completed campaign routes were recorded on the preceding set.
The corrected live replay **passes** in `playtest-artifacts/vow-live-final/final-build-20261004-153859692/`. The ordinary Vow input cancels Lady's real source 9532 before scheduled completion and applies silence from 1791128371374 to 1791128379774 (8,400 ms). No nonphysical active cast is observed during that actual status window, including Thorns. Lady naturally begins the next source Nature Lightning Bolt at 1791128379835, 61 ms after expiry. The fight then defeats Lady with all five actors alive, no XP/loot and no readiness change. Parent and subprocess visually inspect before/after cast screenshots and the boss-defeated panel; loaded character bodies and equipped silhouettes remain visible. No cast-cancel presentation-event capture is claimed. This supersedes the earlier Thorns suppression failure without replacing its historical evidence.
## Remaining limits
- Full Barren clear and Wailing's first-boss route/defeat are verified; full Wailing completion remains unverified.
- Blood Arrow's current CoA base-toggle/cost identity migration, unquantified pair values and Killing Spree's documented simulator approximations remain open in their scoped audits.
- The camera improvement and ordinary right-drag policy are verified at sampled Wailing views; every dungeon viewpoint and compact gameplay layout are not certified by this pass.
## Final hygiene
`npm run release:check` passes 391 changed paths including untracked files in the shared workspace; that count includes preserved work outside this task. The separate vault passes `git diff --check`, and all five owned canonical/worklog/index notes pass trailing-whitespace and exact-one-EOF-newline checks. Scoped harness syntax checks pass. No files are staged or committed by this task.
+120
View File
@@ -0,0 +1,120 @@
# Enemy NPC blocking source audit — 2026-10-05
## Result
The historical AzerothCore source supports ordinary Creature block chance,
block value, aura, and eligibility without a shield or equipped-item check.
Its `Unit::GetUnitBlockChance()` returns zero for Totems; otherwise it starts
at 5 percentage points, adds all `SPELL_AURA_MOD_BLOCK_PERCENT` amounts, and
floors the result at zero. `Creature::GetShieldBlockValue()` uses
`level / 2 + uint32(Strength / 20)`.
This checkout's ordinary Creature initialization never populates the Strength
unit stat. `Creature::SelectLevel` reads `CreatureBaseStats` but assigns health,
mana, base weapon damage, attack power, and ranged attack power only. It does
not call `SetCreateStat` or `SetStat` for Strength. `Creature::UpdateStats` is
a no-op. `Unit::GetStat` reads the zero-initialized `UNIT_FIELD_STAT0`, and
`Object` initializes its unit-value buffer to zero. The core's
`CreatureBaseStats.Strength` column is loaded but has no use in the historical
server game code. For a regular, unmodified Creature in this source tree, the
effective block-value formula is therefore `floor(level / 2)`. The helper
keeps that source-specific zero Strength conclusion explicit instead of
importing the unused class-level Strength column.
The pinned Ascension and Epoch DBC rows for Improved Blocking (3419) both
contain aura type 51 (`SPELL_AURA_MOD_BLOCK_PERCENT`), +75 percentage points,
and a 6,000 ms duration. Applying that aura to a creature raises its base
block chance from 5% to 80% for six seconds. The source spell row does not
require a shield. Existing aura contracts remain the source of the profile
effect value and duration.
## Eligibility in the historical core
- `CREATURE_FLAG_EXTRA_NO_BLOCK` is `0x10`; it prevents block outcomes for
creature templates.
- A normal melee or ranged weapon attack can block only from the front. A
target with an ignore-hit-direction aura bypasses that facing gate.
- A target cannot block while performing a non-melee spell cast or while in
`UNIT_STATE_CONTROLLED` (which includes the controlled/stunned gate).
- The ordinary melee-outcome path starts with integer hundredths of a
percentage point, then subtracts `4 * (attackerWeaponSkill -
defenderMaxSkill)` and requires a positive remaining chance. This is 0.04
percentage points per skill point: higher attacker weapon skill lowers block
chance. `GetMaxSkillValueForLevel` is effective level times five. The helper
maps attacker weapon skill to attacker level times five and creature defense
maximum to creature level times five. The source path does not exclude
ranged weapon attacks from block outcomes.
- The spell hit-table full-block phase has a distinct source gate. `SPELL_ATTR3_COMPLETELY_BLOCKED`
must be set and `SPELL_ATTR0_CU_DIRECT_DAMAGE` must be absent. `ALWAYS_HIT`
and `NO_ACTIVE_DEFENSE` short-circuit the block result. Behind-target,
creature no-block, casting, and controlled checks still apply. A ranged
damage-class spell disables dodge and parry in this path; it does not by
itself disable a source-authorized block.
- Direct physical melee/ranged spells have a later independent damage-block
phase which can coexist with a crit and does not require `COMPLETELY_BLOCKED`.
Its skill modifier has the opposite sign. The continuation imports per-rank
source metadata and implements this phase; see
[`NPC_SPELL_BLOCKING_2026-10-05.md`](NPC_SPELL_BLOCKING_2026-10-05.md).
- `IsTotem()` tests the live UNIT_MASK_TOTEM bit on the runtime object. The
Totem constructor sets this bit; it is not the same data as
`CREATURE_FLAG_EXTRA_NO_BLOCK` and cannot safely be inferred from a creature
template without preserving whether the actor is a runtime Totem.
## Integration data contract
The isolated helper in `src/game/enemyBlocking.ts` takes only values that its
caller can source or resolve at the point of the attack:
- creature level (within the simulator's level-80 boundary);
- active block-aura percentage-point total, including 3419 when active;
- creature template `flags_extra` and the runtime `isTotem` bit;
- whether the party attacker is behind the NPC, whether hit direction is
ignored, and the target's active non-melee cast/controlled/evading states;
- attack packet kind. This helper supports only melee and ranged auto-attacks;
spell and other packets fail closed in this auto-attack helper. The separate
`canEnemyNpcBlockSpell` helper handles imported source spell metadata;
- attacker and creature level, mapped to weapon skill and max defense skill at
level * 5 for the skill adjustment.
Use the raw `blockPercent` returned by `resolveEnemyNpcBlockStats` when calling
`canEnemyNpcBlock`; it applies the skill adjustment to decide whether a block
can occur. Put `enemyNpcBlockChanceAfterSkill`'s result in the shared defender
stats so the common resolver uses the adjusted chance exactly once.
The integration maps stun/fear/confuse to the core CONTROLLED set. It also
treats sleep/blind/knockdown/freeze as unable to defend under HealerMan's
incapacitation model; those extra labels are a simulator approximation rather
than newly verified core unit states. A plain root does not prevent blocking.
Current `MobCombatState` has `level`, `serverEntry`, `activeCast`, status
records, and positions, but it does not itself contain the template
`flags_extra`, runtime Totem identity, or a direct
"attacker is behind" result. This batch's importer now preserves `flags_extra`
in `CreatureTemplateReference`; the runtime resolves it through `serverEntry`
and takes actual facing from the registered transform/spatial provider.
Unknown, summoned, native RoM and character defenders do not inherit this
ordinary-creature baseline. Historical core can block a spell only when
`SPELL_ATTR3_COMPLETELY_BLOCKED` is set and
`SPELL_ATTR0_CU_DIRECT_DAMAGE` is absent; `ALWAYS_HIT`, `NO_ACTIVE_DEFENSE`,
facing, template flag, cast, and controlled checks also matter. Shared
player/party defenders retain their existing source-provided block stats.
## Historical source locations
Read-only reference tree: `../wow-pvt-server-backups-2/azerothcore-wotlk`.
| Source path | Relevant code |
| --- | --- |
| `src/server/game/Entities/Unit/Unit.cpp` | `RollMeleeOutcomeAgainst` checks facing, `NO_BLOCK`, cast/control state, and skill-adjusted chance (around lines 3049–3098); `MeleeSpellHitResult` derives `canBlock` from spell attributes and applies facing/flag/state/skill gates (around lines 3327–3498); `GetUnitBlockChance` implements the 5% + aura creature baseline and Totem exception (around lines 3873–3895). |
| `src/server/game/Entities/Creature/Creature.h` | `Creature::GetShieldBlockValue` is `GetLevel() / 2 + uint32(GetStat(STAT_STRENGTH) / 20)` (around lines 158–161). |
| `src/server/game/Entities/Creature/Creature.cpp` | `Creature::SelectLevel` selects level data and initializes health, mana, weapon damage, and AP but not Strength (around lines 1497–1557). |
| `src/server/game/Entities/Unit/StatSystem.cpp` | `Creature::UpdateStats` returns without changing stats (around lines 1036–1039). |
| `src/server/game/Entities/Unit/Unit.h` | `GetStat` reads `UNIT_FIELD_STAT0`; `GetMaxSkillValueForLevel` returns effective level times five (around lines 1058–1059 and 1204). |
| `src/server/game/Entities/Unit/Unit.cpp` | `Unit` initializes its create-stat values to zero (around line 413). |
| `src/server/game/Entities/Object/Object.cpp` | Object value fields, including Unit stat fields, start zeroed (around lines 115–116). |
| `src/server/game/Entities/Creature/CreatureData.h` | `CREATURE_FLAG_EXTRA_NO_BLOCK = 0x10`; `CreatureBaseStats` includes a Strength column (around lines 50 and 297–305). |
| `src/server/game/Entities/Totem/Totem.cpp` | Runtime Totem construction sets `UNIT_MASK_TOTEM` (around lines 27–29). |
| `src/server/game/Entities/Unit/Unit.h` | `IsTotem()` checks the live `UNIT_MASK_TOTEM` (around line 799). |
The exact pinned spell signatures and hashes for 3419 in both profiles are
recorded in [`STOCKADE_ENEMY_BUFFS_2026-10-05.md`](./STOCKADE_ENEMY_BUFFS_2026-10-05.md).
+152
View File
@@ -0,0 +1,152 @@
# Ordinary enemy block aura parity — 2026-10-06
## Implemented contract
[`src/game/enemyBlockAuras.ts`](../src/game/enemyBlockAuras.ts) records the
source-backed aura inputs used by ordinary AzerothCore Creature blocking:
- Aura 51 (`SPELL_AURA_MOD_BLOCK_PERCENT`) adds its percentage-point amount to
the ordinary creature's 5% block chance.
- Aura 253 (`SPELL_AURA_MOD_BLOCK_CRIT_CHANCE`) contributes to the separate
critical-block roll after a block succeeds. The summed amount is truncated
to an integer for `roll_chance_i`; a successful critical block doubles the
block value, then the ordinary damage cap applies.
- Aura 288 (`SPELL_AURA_IGNORE_HIT_DIRECTION`) bypasses the facing check. It
does not bypass the independent eligibility gates. The hit-table full-block
spell path still honors `CU_REQ_CASTER_BEHIND_TARGET`; the post-hit direct
spell path does not add that separate attribute check.
`resolveEnemyNpcBlockAuraInputs` returns target-local active values as
`blockChanceAuraPercent`, `criticalBlockChancePercent`, and
`ignoresHitDirection`. It sums aura amounts and ignores expired or other-
target auras. `enemyNpcCriticalBlockChanceForRoll` and
`enemyNpcBlockValueAfterCritical` expose the integer roll argument and the
post-roll multiplier as pure helpers. The caller must first resolve a block,
then make the independent critical-block roll.
`supportedEnemyBlockAuraDefinition` returns an importable full-spell aura only
when every DBC effect is represented. On these source rows, only Improved
Blocking (3419) meets that rule. Critical Block (47294–47296) and Deterrence
rows retain their full source signatures and explicit unsupported-sibling
lists; `enemyBlockAuraInputDefinition` is only for a block-input fixture or a
deliberately modeled passive. It must not be treated as an imported complete
spell definition.
## Raw source rows
The three Spell.dbc files below each have 234 fields. The parser's localized
field shift applies only at 239 fields, so these rows use shift 0. Aura effects
below are effect type 6, implicit targets 1/0, mechanic 0, radius 0, and period
0 unless otherwise stated. Base points are the parsed client amount
(`basePoints` field plus one). Duration index 0 means permanent; the runtime
contract represents that as `durationMs: null`.
| Spell | Profile | Duration | Present effects (`auraType:basePoints:miscValue`) |
| --- | --- | ---: | --- |
| 3419 Improved Blocking | WoW 3.3.5a, Ascension, Epoch | 6,000 ms | `51:75:0` |
| 47294 Critical Block | WoW 3.3.5a | permanent | `253:20:0`, `107:5:7` |
| 47295 Critical Block | WoW 3.3.5a | permanent | `253:40:0`, `107:10:7` |
| 47296 Critical Block | WoW 3.3.5a | permanent | `253:60:0`, `107:15:7` |
| 47294 Critical Block | Ascension | permanent | `253:100:0`, `107:4:7`, `107:8:3` |
| 47295 Critical Block | Ascension | permanent | `253:100:0`, `107:7:7`, `107:16:3` |
| 47296 Critical Block | Ascension | permanent | `253:100:0`, `107:10:7`, `107:25:3` |
| 47294–47296 Critical Block | Epoch | permanent | Same as the corresponding WoW 3.3.5a row |
| 67801 Deterrence | WoW 3.3.5a, Epoch | 5,000 ms | `288:100:0`, `185:-100:0` |
| 67801 Deterrence | Ascension | 60,000 ms | `288:100:0`, `4:0:0`, `27:0:0` |
| 667801 Deterrence | Ascension | 5,000 ms | `288:100:0`, `185:-100:0`, `27:0:0` |
| 1167801 Deterrence | Ascension | 5,000 ms | `288:100:0`, `185:-100:0` |
This preserves an important profile difference: the stock and Epoch Critical
Block rows contain one aura-107 sibling; Ascension contains two. No effect 2
is present on the stock or Epoch rows. Aura 107 effects are preserved as
unsupported effects because this contract implements critical-block chance,
not their separate flat spell modifiers (`SPELLMOD_CRITICAL_CHANCE`, misc 7,
and Ascension `SPELLMOD_EFFECT1`, misc 3). Deterrence's effects besides aura
288 are also preserved, not silently dropped.
A bounded follow-up found that the pinned core's `ApplySpellMod` returns for
non-player targets (`SpellAuraEffects.cpp:813–816`), after aura 107 reaches the
spell-modifier path. These siblings are therefore no-ops on that ordinary
Creature self-buff path. This pass retains the complete-import gate because the
shared definition API does not enforce that actor/target restriction; a future
NPC-only importer can use an explicit ordinary-Creature self-target guard. This
is not evidence for player/party handling or external custom script overrides.
The source file SHA-256 is
`107369aa671a26d68081fc65b0066cb00b2cd80dfa2174ddf55bd5919d5db772`;
`SpellDefines.h` is
`635a025f615e16b6f10f39aa32d523f9b3d6df3959fdd0e4b49a8250da1db48f`.
The local inputs and SHA-256 pins are:
| Profile | Spell.dbc path | SHA-256 |
| --- | --- | --- |
| WoW 3.3.5a | `../wow-pvt-server-backups-2/wow335a/Data/patch-A.MPQ/DBFilesClient/Spell.dbc` | `57011d528fd66cf39f5ab6fb168e389ab9e4cc1b8050f7201a54239d489b415c` |
| Ascension | `../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc` | `2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce` |
| Epoch | `../HealerMan-Storage/pipeline-work/dungeons/epoch-client/DBFilesClient/Spell.dbc` | `d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3` |
All duration indexes use
`../LadiksMPQEditor/client-current/patch-S/DBFilesClient/SpellDuration.dbc`,
SHA-256 `eeae44ef0185924f3d6ec57ab2701c66566db86e51ab0bae017a9449126eb3a0`.
The parsed durations are index 32 = 6,000 ms, index 28 = 5,000 ms, and index
3 = 60,000 ms.
## Non-direct full-hit block boundary
One non-direct row is source-proven for a bounded WoW 3.3.5a helper:
Shield Bash (spell 72) has damage class 2, school mask 1, `attributes0=327696`,
`attributes3=8` (`COMPLETELY_BLOCKED`), and present effects 68 and 64. Neither
effect is in the pinned core's direct-damage effect list. The pinned
`creature_template_spell.sql` assigns spell 72 to creature entries 1540 and
3739 (rows 582 and 1442).
The AzerothCore checkout is pinned at commit
`e822d718322289dd036fb2daf8867ba41283bf9a`. `SpellMgr.cpp:3214–3222` derives
`CU_DIRECT_DAMAGE` from its explicit direct/heal effect list;
`SpellMgr.cpp:3440–3470` sets `CU_REQ_CASTER_BEHIND_TARGET` from an explicit
spell-ID list that does not include 72. The shipped
`data/sql/base/db_world/spell_custom_attr.sql` and the checked active world SQL
updates contain no spell-72 override. The source correction path has no
spell-72 custom-attribute correction, and no loaded module replaces the
custom-attribute hook in this checkout. These checks prove only the two
blocking-relevant bits for this exact source snapshot. The helper records a
known-bit mask and zero value for those bits; it does not claim that the full
computed `AttributesCu` word is zero.
This contract is available only for spell 72 with the `wow335` source profile.
It is not an Ascension/Epoch assertion and is not a generic inference from a
DBC row. Other non-direct candidates remain gated until their exact server
custom-attribute evidence is imported. A database or core correction outside
the pinned checkout can change this result.
`enemyNpcSourceSpellBlockMetadata(72, "wow335")` returns the metadata used by
the pure phase classifier. It proves only the two block-relevant
`AttributesCu` bits through `customAttributeEvidence.knownMask/value`; it never
fills the unknown remainder of the custom word. The helper returns no row for
other IDs or source profiles. Its phase and facing-gate behavior has focused
unit coverage, but no source NPC non-direct spell importer/application has
been wired in this pass, so this is not runtime Shield Bash coverage.
## Historical core pins
Read-only source: `../wow-pvt-server-backups-2/azerothcore-wotlk`, commit
`e822d718322289dd036fb2daf8867ba41283bf9a`.
| Source | Verified behavior |
| --- | --- |
| `src/server/game/Spells/Auras/SpellAuraDefines.h:114,316,351` | Aura IDs 51, 253, and 288. |
| `src/server/game/Entities/Unit/Unit.cpp:3276–3307` | Post-hit spell block checks front-or-aura and the critical-block roll uses `roll_chance_i(GetTotalAuraModifier(...253))`. |
| `src/server/game/Entities/Unit/Unit.cpp:1579–1590,1879–1887` | Successful block removes block value; a successful critical-block roll doubles it. The direct spell packet can already be critical. |
| `src/server/game/Entities/Unit/Unit.cpp:3364–3396` | Hit-table full block requires the blockable attribute and absence of the direct-damage custom bit; the behind-required custom bit limits the aura-facing exception. |
| `src/common/Utilities/Random.h:63–66` | `roll_chance_i` compares an integer chance with an inclusive 0–99 roll. |
| `src/server/game/Spells/SpellMgr.cpp:3214–3222,3440–3470` | Direct-damage effect derivation and the explicit caster-behind spell list. |
| `data/sql/base/db_world/creature_template_spell.sql:582,1442` | Source NPC spell assignments for Shield Bash spell 72. |
## Validation
Focused source-aura, block-helper, and `damageMob` integration tests are
`src/game/enemyBlockAuras.test.ts`, `src/game/enemyBlocking.test.ts`, and
`src/game/enemyBlockAuraRuntime.integration.test.ts`. They verify profile rows,
unsupported siblings, target-local duration behavior, behind-facing aura
input for player and party attacks, the separate critical-block result, and
the native RoM exclusion. The no-block flag is covered in the pure source gate
tests in `enemyBlocking.test.ts`.
@@ -0,0 +1,94 @@
# Ordinary Creature Critical Block imports — 2026-10-06
## Import boundary
`src/game/enemyBlockAuras.ts` keeps
`supportedEnemyBlockAuraDefinition` fail-closed for Critical Block
(47294–47296) and Deterrence. The separate
`ordinaryCreatureSelfTargetCriticalBlockAuraDefinition` guard admits only
Critical Block after the caller supplies an
`EnemyNpcCriticalBlockImportProof` for one ordinary Creature self-cast. The
defender, caster, and target IDs must be the same nonempty ID; the proof must
explicitly identify an ordinary Creature and exclude a native defender, a
summon, and a character defender. It also carries the bounded applicability
token `azerothcore-e822d718-default-spellmod-path`.
The guard validates the complete raw spell signature, runtime contract, block
chance, and the exact aura-107 sibling list against the reviewed profile/rank
row before returning an aura-253 runtime definition. Aura 107 stays present in
the source signature and unsupported-effect metadata. Its no-op behavior is
specific to the reviewed default core path; a custom aura script/module or a
private server override invalidates that applicability proof. The WoW,
Ascension, and Epoch labels identify client DBC rows. They do not certify
private server overrides for those clients. Player and party casts must never
use this full-import guard.
## Reviewed Spell.dbc signatures
Each listed effect is type 6, mechanic 0, target A/B 1/0, radius 0, period 0;
spell range index is 1, school mask is 1, damage class is 0, duration is
permanent (`-1` in the raw signature), and stack amount is 0. The parsed
`basePoints` below are the client amount (`Spell.dbc` base-points field plus
one). The Spell.dbc hashes and source paths are pinned in
`NPC_BLOCK_AURA_PARITY_2026-10-06.md`.
| Profile | Spell | Aura effects (`auraType:basePoints:miscValue`) |
| --- | ---: | --- |
| WoW 3.3.5a | 47294 | `253:20:0`, `107:5:7` |
| WoW 3.3.5a | 47295 | `253:40:0`, `107:10:7` |
| WoW 3.3.5a | 47296 | `253:60:0`, `107:15:7` |
| Ascension | 47294 | `253:100:0`, `107:4:7`, `107:8:3` |
| Ascension | 47295 | `253:100:0`, `107:7:7`, `107:16:3` |
| Ascension | 47296 | `253:100:0`, `107:10:7`, `107:25:3` |
| Epoch | 47294 | `253:20:0`, `107:5:7` |
| Epoch | 47295 | `253:40:0`, `107:10:7` |
| Epoch | 47296 | `253:60:0`, `107:15:7` |
Aura 253 supplies the modeled critical-block chance. Aura 107 is
`SPELL_AURA_ADD_FLAT_MODIFIER`; misc 7 is the spell critical-chance modifier,
and Ascension also has misc 3 (`SPELLMOD_EFFECT1`). In the pinned AzerothCore
checkout at commit `e822d718322289dd036fb2daf8867ba41283bf9a`,
`SpellAuraEffects.cpp:780` sends aura spell modifiers through `ApplySpellMod`.
`ApplySpellMod` returns at lines 813–816 when the target is not a player, so
these aura-107 spell modifiers do not apply to an ordinary Creature on that
default path. This evidence does not cover custom aura scripts, custom modules,
or external server changes.
## Source assignment availability
The pinned AzerothCore base `creature_template_spell.sql` dump and checked
`db_world` SQL updates contain no `Spell` assignment for 47294, 47295, or
47296. This pass adds an importer guard and its evidence only; it does not
assign Critical Block to a creature. A real source creature assignment is
still required before any NPC receives the buff. Do not infer or fabricate one
from the player talent spell rows.
Deterrence remains outside the full importer because its source signatures
also contain effects (including aura 185 or aura 27) that are not represented
by ordinary NPC block inputs.
## Focused coverage
`src/game/enemyBlockAuras.test.ts` covers all three ranks in all three client
profiles, missing and malformed proof, mismatched self-target IDs, native,
summoned, and character-defender exclusions, the pinned applicability token,
generic importer fail-closed behavior, Deterrence exclusion, and raw signature
drift. The focused command is:
```text
npx vitest run src/game/enemyBlockAuras.test.ts
```
`combatStore.ts` uses this guard only for an ordinary source Creature's
self-target descriptor with a known template entry. The compiler pins all
three rank signatures in Ascension/Epoch, including aura-107 siblings, and
validates them even when no source NPC assignment uses them. Its duration-index
0 parser sentinel is 0; the guarded runtime definition normalizes the source
permanent aura to an `expiresAt=null` lifetime.
`enemyCriticalBlockImport.integration.test.ts` passes two actual runtime tests:
a clearly labeled synthetic self-cast applies the permanent aura without
damage, produces a deterministic critical block, and clears on reset; native,
summoned, character and non-self fixtures are excluded. This synthetic fixture
does not establish a real creature assignment. Regenerated campaign data is
byte-for-byte unchanged from this pass's starting snapshot.
+229
View File
@@ -0,0 +1,229 @@
# Ordinary WoW NPC spell blocking — 2026-10-05
## Result
The historical AzerothCore source has two spell-block phases. They use
different eligibility rules and different skill signs, so the pure helpers in
[`src/game/enemyBlocking.ts`](../src/game/enemyBlocking.ts) keep them separate.
The existing melee/ranged auto-attack baseline is unchanged. Native RoM NPCs,
unknown sources, and character defenders do not use this ordinary-Creature
spell path.
The current imported spell metadata supports the post-hit direct-damage phase
when source effects positively establish AzerothCore's `DIRECT_DAMAGE`
custom flag. It does not infer that custom flag is absent from a Spell.dbc row.
The separate hit-table full-block phase therefore requires an explicit
AzerothCore-computed custom-attribute word and remains unavailable where that
word has not been imported.
## Runtime implementation
`scripts/generate-wow335-abilities.mjs` now retains the exact defense metadata
on every imported rank. Its 239-field WoW client records use the existing
six-column shift: damage class is field 219 and school mask is field 231.
Raw Heroic Strike, Steady Shot and Arcane Shot records independently confirm
those columns. Regeneration changed only this metadata and the generation
timestamp; all previous spell effects, progression and costs remain identical.
`wow335AbilityCatalog.ts` and the classic Ascension builder in
`coaAbilityCatalog.ts` preserve those scalars. `abilityAtLevel` selects the
rank's own metadata and clears it when that rank is unbound.
`combatStore.ts` routes source-bound direct physical melee/ranged packets from
both the player and real party companions through the ordinary NPC defender.
`partyRuntime.ts` supplies the exact source damage class and selected spell
rank to that resolver for blockable physical casts against ordinary source
NPCs; those casts previously used a damage path without a hit-result context.
The damage API uses the explicitly selected spell ID to look up that rank's
defense metadata and leaves unknown IDs unbound.
It resolves current NPC facing, active non-melee casts, control, source
`flags_extra`, block auras and returning/evading state. Weapon skill uses the
simulator's existing level-times-five abstraction; no weapon-skill progression
or equipment requirement is introduced. Native RoM targets, guardians and
character defenders retain their separate paths. Native RoM spells never
acquire WoW metadata through their stat-ruleset choice.
`combatResults.ts` adds an explicit `blockMode: post-hit`. The common hit/crit
table contains no block entry for this mode. An independent `block` roll runs
only after a physical melee/ranged hit lands, subtracting NPC block value after
critical and armor mitigation. Crit-plus-block retains `outcome: crit`,
`critical: true` and `blocked: true`; a regular blocked hit reports `block`.
Structured outgoing damage events retain `blocked` and `blockedAmount`, so
recorders can observe both properties without guessing from the latest result.
Ordinary autoattacks retain their single table roll.
Unknown source packets, periodic ticks, magical schools, source damage-class
mismatches and defense-exception spells do not enter this new phase. Runtime
full-hit blocking of non-direct spells, ignore-hit-direction aura imports and
critical-block aura doubling remain source-integration boundaries. This pass
does not implement the other spell-specific dodge/parry attribute exceptions.
The level-80 cap, Ready-five policy and loot scope remain unchanged.
## Validation
The ten directly affected Vitest files pass 134 checks: source helper gates,
shared combat results, post-hit block distribution/order, per-rank metadata,
stance/autoattack regression, native RoM exclusion, actual player and generated
party spell casts, party AI/runtime and stat-ruleset regressions. The six new
store integration cases prove Heroic Strike and a real Hunter companion's
Steady Shot can critically hit and block simultaneously. They preserve exact
event flags/amounts, source flags=0, actual selected rank versus unknown rank
IDs, magical spell exclusion and rear/cast/control gates. Guaranteed crit and
one-damage companion engagement are labeled synthetic fixtures; creature and
spell fields remain real. NO_BLOCK is covered by the pure helper because no
current reference template carries that flag.
Ready-five passes seven additional Vitest and twenty Python checks. The final
8 GB TypeScript/Vite production build, pre/postbuild audits, compression and
release-bundle verification pass; the subsequent TypeScript check includes
the final integration test file. Independent Luna review found no concrete
defect. Ordinary runtime callers have no modeled unsummoned Totem identity;
that subtype must be exposed if such static dungeon actors are added.
The frozen production copy has 5,964 files, 116,755,437 bytes and aggregate
SHA-256 `864781d16c3c0a26457b6acd7a9bd31357116f856e6b27258b5b633d2f224fac`.
Mutable dist stayed identical before/after the verified copy. The scoped
one-boss browser run `20261005-202545227` clears Cellblock Rush in 03:18.0,
Easy/Normal, with Hamhock (`creature-79098`) as its actual seeded objective.
Required and killed IDs agree 1/1, all five actors finish alive and no death or
resurrection recovery is observed. Nine effective heals total 2,801.9 HP.
Six party-to-hostile blocks include two Revenge and two Sinister Strike spell
hits, with event-level block amounts; one correlated Revenge result explicitly
records the independent post-hit roll. No live crit-plus-block was captured;
that behavior remains deterministic integration evidence. Snapshots sample the
latest 200-event ring and are not a lossless stream.
The frozen build and complete content manifest stay unchanged. All 2,124
served content objects match their hash addresses and manifest references.
Root reviewed roster, entrance, route and native results screenshots: bodies
and equipped silhouettes render, while close-party overlap, edge occlusion and
compact-roster name clipping remain visible. Page errors are zero; the only
console item is a favicon 404. Exact provenance, preserved failed entrance
attempt and cleanup are in
`docs/STOCKADE_SPELL_BLOCKING_PLAYTEST_2026-10-05.md`.
## Core spell gates
`Unit::SpellHitResult` dispatches melee and ranged damage-class spells through
`Unit::MeleeSpellHitResult`; magic and unclassified damage spells use another
path. The spell damage-class values are 0 (none), 1 (magic), 2 (melee), and 3
(ranged). The normal physical school mask is bit `0x1`.
The hit-table phase can return a full `SPELL_MISS_BLOCK` only when all of these
source gates allow it:
- Damage class is melee or ranged, so the spell uses `MeleeSpellHitResult`.
- `SPELL_ATTR3_COMPLETELY_BLOCKED` is set (`attributes[3] & 0x8`).
- AzerothCore's computed `SPELL_ATTR0_CU_DIRECT_DAMAGE` is absent
(`customAttributes & 0x100` is zero).
- Neither `SPELL_ATTR3_ALWAYS_HIT` (`attributes[3] & 0x40000`) nor
`SPELL_ATTR0_NO_ACTIVE_DEFENSE` (`attributes[0] & 0x200000`) is set.
- An attack from behind disables block unless the victim has
`SPELL_AURA_IGNORE_HIT_DIRECTION`. If the spell has the core custom flag
`SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET` (`customAttributes & 0x20000`),
that aura does not bypass the hit-table facing check.
- Creature template `flags_extra` does not include
`CREATURE_FLAG_EXTRA_NO_BLOCK` (`0x10`), and the victim is not a Totem.
- The skill-adjusted block chance remains positive, and the victim is not
performing a non-melee spell cast or in `UNIT_STATE_CONTROLLED`.
The hit-table roll runs after miss and mechanic-resist checks. Its block chance
is truncated to integer hundredths before applying skill difference:
`int32(blockChance * 100) - skillDiff * 4`, where
`skillDiff = attackerWeaponSkill - defenderMaxSkill`. This subtracts 0.04
percentage points per skill point. AzerothCore uses level times five for the
defender's max skill; ranged non-weapon spells also use attacker level times
five, while other cases use the attacker's actual attack-type weapon skill.
Apply the adjustment before checking whether chance is positive: a raw chance
of zero can become positive when attacker skill is below defender maximum.
The post-hit phase handles direct physical spell packets after they have landed.
`SpellMgr` marks direct effects with `SPELL_ATTR0_CU_DIRECT_DAMAGE`; its effect
list includes school damage (2), weapon damage without school (17), weapon
percent damage (31), weapon damage (58), normalized weapon damage (121), and
healing (10). For an incoming damage packet, `Unit::CalculateSpellDamageTaken`
attempts this later block only when damage class is melee or ranged and the
packet school includes physical bit `0x1`. It does not require
`SPELL_ATTR3_COMPLETELY_BLOCKED`.
The later `Unit::isSpellBlocked` path bypasses block for `NO_ACTIVE_DEFENSE` or
`ALWAYS_HIT`; otherwise it requires a front-facing victim or an active
ignore-hit-direction aura, no `NO_BLOCK` creature flag, a positive chance, and
no non-melee cast or controlled state. It does not independently inspect
`CU_REQ_CASTER_BEHIND_TARGET`. Its chance formula is the float expression
`blockChance + (attackerWeaponSkill - defenderMaxSkill) * 0.04`, so higher
attacker skill raises this post-hit block chance. A successful block subtracts
the creature's block value from damage and can coexist with a critical hit.
If the block consumes all damage, Spell.cpp can report the result as
`SPELL_MISS_BLOCK`.
Apply the skill adjustment before checking positivity here as well; a zero raw
chance can become positive when attacker skill exceeds defender maximum.
`SPELL_ATTR7_NO_ATTACK_DODGE` (`attributes[7] & 0x00800000`) and
`SPELL_ATTR7_NO_ATTACK_PARRY` (`attributes[7] & 0x01000000`) suppress those
avoidance results only; they do not disable block. School alone does not make
a magic-class spell blockable, and ranged damage class does not by itself
disable a source-authorized block.
## Spell metadata and helper contract
`EnemyNpcSpellDefenseMetadata` mirrors the exact metadata fields added to
source-backed ability ranks: `damageClass`, `schoolMask`, `attributes0`,
`attributes3`, `directDamageFromEffects`, and `sourceProfile`. The helper also
accepts optional `customAttributes` for callers that have a sourced or
reconstructed AzerothCore custom word. Without that word, a non-direct spell
classifies as `none`; a client DBC row alone cannot prove that SQL or server
corrections did not set a custom flag.
- `classifyEnemyNpcSpellBlockPhase` returns `direct-damage` only with positive
direct-effect evidence, a melee/ranged class, and physical school bit; it
returns `hit-table` only when explicit custom attributes show the direct
flag is absent and the blockable-spell attribute is present.
- `enemyNpcSpellBlockChanceAfterSkill` takes the attacker's actual weapon skill
and defender level. This avoids inventing a weapon requirement or guessing
skill from spell DBC equipment masks.
- `canEnemyNpcBlockSpell` applies Totem, `NO_BLOCK`, direction, cast/control,
and positive skill-adjusted chance gates for either phase.
The source-profile type currently accepts `wow335` and `ascension`, matching
the imported spell-rank metadata contract. The pinned Epoch Spell.dbc is
available for adjacent aura and stance contracts, but this helper does not
accept Epoch rank metadata until that profile is included in the importer
contract.
Two direct-effect candidates have exact local profile rows:
| Spell | WoW 3.3.5a | Ascension patch-D | Epoch |
| --- | --- | --- | --- |
| Heroic Strike (78) | class 2, school 1, attrs0 327700, attrs3 1024, weapon damage effect 58 | class 2, school 1, attrs0 327700, attrs3 1024, weapon damage effect 58 | same as WoW 3.3.5a |
| Steady Shot (56641) | class 3, school 1, attrs0 4259858, attrs3 0, direct effect 2 | class 3, school 1, attrs0 65554, attrs3 0, direct effects 2 and 31 | same as WoW 3.3.5a |
These effects positively establish the direct custom flag under the historical
core's SpellMgr effect rules. Ascension's Steady Shot has a different set of
attribute words and a weapon-percent-damage effect, but retains ranged
class and physical school. The helper does not hard-code these spell IDs.
## Pinned source locations
Read-only historical core: `../wow-pvt-server-backups-2/azerothcore-wotlk`.
| Source | Relevant code |
| --- | --- |
| `src/server/game/Entities/Unit/Unit.cpp` | `MeleeSpellHitResult` at 3330–3500; `isSpellBlocked` at 3276–3299; `CalculateSpellDamageTaken` at 1508–1640; dispatch by damage class at 3680–3770; `GetUnitBlockChance` at 3873–3895. |
| `src/server/game/Spells/SpellInfo.h` | Core custom flags including `CU_DIRECT_DAMAGE = 0x100` and `CU_REQ_CASTER_BEHIND_TARGET = 0x20000` near 185–194. |
| `src/server/shared/SharedDefines.h` | `NO_ACTIVE_DEFENSE = 0x200000`, `COMPLETELY_BLOCKED = 0x8`, `ALWAYS_HIT = 0x40000`, and damage-class values near lines 391, 484, 499, and 1552; no-dodge/no-parry attributes near 652–653. |
| `src/server/game/Spells/SpellMgr.cpp` | Computes `CU_DIRECT_DAMAGE` for the listed effect types near 3210–3230. |
| `src/server/game/Spells/Spell.cpp` | Applies post-hit block output after spell damage calculation near 2760–2820. |
The source profile pins are already recorded by
[`enemySourceAuras.ts`](../src/game/enemySourceAuras.ts) and
[`enemyStances.ts`](../src/game/enemyStances.ts): Ascension patch-D Spell.dbc
SHA-256 `2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce`,
and Epoch Spell.dbc SHA-256
`d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3`. The WoW
3.3.5a candidate rows above came from
`../wow335a/Data/enUS/patch-enUS.MPQ` Spell.dbc. Their raw row fields are
parsed by `scripts/generate-wow335-abilities.mjs` at DBC fields 4–11
(attributes), 213 (damage class), 225 (school), and 71–73 (effects), including
the six-field schema shift for newer DBC records.
The extracted stock Spell.dbc is 46,699,377 bytes, 46,583 rows and 239 fields,
SHA-256 `9f0088da35c5ed0b5106cd20e422611489e435b74043e520e02221e0ce1b1af1`.
+46
View File
@@ -0,0 +1,46 @@
# Performance check — 2026-10-04
> **Current QA policy (2026-10-05):** Routine live tests use Stormwind Stockade: Cellblock Rush (`bite-sized-stormwind-stockade`); record the boss selected from the run ID. Full-source Stockade campaigns require explicit route selection. The Wailing captures and commands in this dated report remain historical; follow [the current test policy](TEST_DUNGEON_POLICY.md) and root `AGENTS.md`. A new Wailing reproduction needs an explicit owner request.
## Findings and changes
- **CPU:** The production CPU profile spent about 925 ms of an eight-second sample inside `filesForContentPack`, which repeatedly scanned and sorted the asset catalog. `src/content/contentManifest.ts` now indexes each immutable file map once through a WeakMap. `src/content/contentManager.ts` caches usable/unavailable pack results until the next content publication; install, removal, validation, and catalog changes invalidate those results.
- **Idle CPU/rendering:** `src/ui/usePresentationClock.ts` stops HUD, aura, and periodic-effect clocks while locally paused, viewing the map/companion, or hidden. Visible shared-online timers still run behind menus. `DungeonRaceHud.tsx` no longer starts its two clocks during ordinary dungeon play. Aura and periodic strips use shallow target-filtered subscriptions, and aura timer effects no longer restart on every new filtered array.
- **Retained RAM:** `src/game/combatAudio.ts` previously retained every decoded cue for the tab lifetime. Its least-recently-used cache now holds at most 64 entries or 32 MiB of decoded PCM. Active playback keeps its own buffer, failed requests can retry, and simultaneous requests share a decode. This limits cache retention, not total browser memory or all in-flight audio allocations.
- **GPU:** Local pause and hidden-page handling already switch the scene to demand rendering and stop physics. The checked stable pause/background samples made zero WebGL draw calls. No rendering-resolution, texture-quality, lighting, or culling reductions were applied.
## Measurements
Production builds were exercised in headless Edge on the AMD Radeon RX 9070 XT, at a 1280 × 800 viewport with a 1920 × 1200 drawing buffer. `scripts/playtest-performance.cjs` creates a temporary local account/database, enters Wailing Caverns, samples entry combat and movement, pauses/resumes, exercises synthetic page visibility, and repeats entry/exit three times. The historical label `active-idle` means no player input; companions may fight during that sample.
| Sample | Before | After | Confirmation |
|---|---:|---:|---:|
| Entry main-thread busy time | 77.7% | 44.2% | 61.7% |
| Movement-following main-thread busy time | 79.2% | 69.0% | 55.6% |
| Stable 20-second pause busy time | 5.41% | 0.49% | 0.46% |
| Stable pause draw calls/second | 0 | 0 | 0 |
| Stable pause JavaScript heap | 192.57 MiB | 173.26 MiB | 173.06 MiB |
| Third menu return JavaScript heap | 59.88 MiB | 59.59 MiB | 59.71 MiB |
These are individual route samples, not a deterministic combat benchmark. NPC appearances, combat progression, loaded effects, and concurrent project work vary. The heap difference and active draw-call difference must not be attributed entirely to these fixes. The CPU profile confirms removal of the catalog-scan hotspot; the stable pause results reproduce.
A separate lookup benchmark used the same 21,585-file manifest and 2,181-file combat-media pack for both algorithms: 100 old scan/sort lookups took 746.06 ms; building the new index took 14.91 ms once; 100 cached lookups took 0.023 ms. This isolates the catalog work, not total game speed.
The after run's synthetic hidden sample used 0.43% main-thread busy time and zero draw calls; resume restored continuous rendering. JavaScript heap changed only 0.024 MiB over its stable paused 20-second window. Menu returns released most scene heap and backing storage across three cycles. No page errors occurred.
One third-cycle pause window still showed a transient workload (12.3% main-thread busy time and 226 draw calls/second) despite demand mode. The confirmation run adds a paused CPU profile and an additional 20-second settled sample: both its initial third-cycle pause and settled window had zero draws and no layouts. The settled window used 0.50% main-thread busy time; the paused profile was overwhelmingly idle. This transient was not reproduced or conclusively attributed, so pause is not certified draw-free during every asynchronous transition.
## Validation and evidence
- 59 focused tests passed across content validation/persistence, audio, aura/periodic displays, scene lifecycle, and disposal. Audio regressions specifically cover byte/count eviction, concurrent reuse, failure retry, and active playback.
- `npm run build` passed TypeScript, Vite, KTX2 and environment-performance audits, compression, and release-bundle verification. The environment audit reported zero regressions across 106 assets, with 60 existing budget exceptions.
- `npm run release:check` passed. An initial attempt raced another task writing a document; the subsequent check passed without changing unrelated work.
- Visually inspected active and resumed gameplay and pause screenshots: character bodies, starter gear, enemies, effects, and HUD remained visible. This is not an equipment or character-rendering change.
- Raw measurements/screenshots/profiles: `artifacts/playtest/performance/before/`, `after/`, and `confirmation/`. Each run contains `results.json`, `renderer.json`, active/pause screenshots, and `active.cpuprofile`; confirmation also contains `paused.cpuprofile`.
- Repeat with `node scripts/playtest-performance.cjs`; set `PERFORMANCE_LABEL` for a separate evidence directory. `PERFORMANCE_URL` can point the same UI route at a local preview, but production mode is necessary to exercise installed-content checks.
## Limits and remaining targets
Main-thread busy percentage is one browser thread's occupied wall time, not whole-system CPU utilization. Forced-GC JavaScript heap and backing storage are not total process RAM, GPU memory, or VRAM. Draw calls measure submitted rendering work, not device GPU utilization. Hidden-page handling is a synthetic lifecycle test, not an OS background-throttling measurement.
This pass covers one desktop dungeon route, not every dungeon, mobile/Android, high-shadow/resolution settings, shared-online play, or a long combat soak. Original-effect graph and texture caches still retain distinct media for the tab lifetime; safe eviction needs a separate varied-spell/resource-ownership check. Remaining active profile cost is primarily rendering, transforms, and layout; larger scene and device-level GPU profiles should guide any further visual changes.
+33
View File
@@ -0,0 +1,33 @@
# RoM Barren Caves final-build clear — 2026-10-04
## Outcome
The final build completed Barren Caves through ordinary WASD movement and combat inputs. The native results overlay displayed **FULL DUNGEON CLEAR**, “Barren Caves complete,” and **Anglo — Defeated**, with **Bosses defeated 1/1** and a displayed time to final boss of **13:36.9**. The overlay screenshot and route telemetry agree: Anglo is recorded as a level-36 boss at 0/152,256 health and dead. The overlay appeared during movement at checkpoint 358/376, after 697.18 m of 717.47 m expected route distance; native completion ended movement, so the clear claim is based on the result UI and dead-boss state, not arrival at the guide endpoint.
## Run and build
- Harness: `node scripts/playtest-campaign-boss-pass.cjs --route=barren-caves --campaign-boss-route --max-campaign-seconds=1200`. Source confirms `--max-campaign-seconds` sets the campaign route deadline; `--route-seconds` applies to the non-campaign route path.
- Final-build assets reported by the build: `index-DHQInfBp.js`, `combatStore-Cx06rFzG.js`, `GameRuntime-D87YWi4Q.js`, `PartyFrames-5jlxKxxK.js`, `romAbilityCatalog-CHjYfHkT.js`, and `index-499eecpe.css`. The harness result manifest confirms it loaded the final `index`, `combatStore`, `GameRuntime`, and `PartyFrames` JavaScript modules.
- The harness created an isolated level-30 UI profile, Routepriestq (RoM Priest / Knight, healer), and isolated temporary browser/server data. Level gains to 36 were natural XP. No readiness promotion or loot action occurred.
- Navigation used normal WASD inputs for 728 movement steps. 358 of 376 checkpoints were verified before the native result overlay stopped input. The final overlay remained visible in the captured boss-arrival screenshot.
## Party, healing, and combat
The player survived at level 36 with 2,629.45/2,629.45 health. Caelan survived at 1,190.57/2,909.79, Durnik at 2,289.97/2,289.97, and Veyra at 2,343.25/3,081.81. Rorik was the sole party death at 0/3,679.16. The healer produced **46,328.47 effective healing** across 79 healing actions with a positive healing event (97 healing inputs were recorded). The harness observed 41 distinct dead mobs, including Anglo.
The largest player-to-living-party-member separation in periodic route samples was 12.52 m. The largest recorded after-pack-consolidation separation was 15.56 m. The boss was killed by natural party combat; the harness’s direct boss-fight handler did not run because the native full-clear overlay had already appeared.
## Visual and error review
Inspected the roster desktop and compact screenshots, entrance, 25%, 50%, 75%, and boss-arrival screenshots. Character bodies and held starter weapon silhouettes (staff, shield, and other weapons) remain visible in the roster and dungeon. Clothing is sparse on the displayed avatars. The full-clear panel is legible over the dimmed dungeon and names Anglo as defeated.
The route record has no page or console errors. The aggregate run manifest contains one `favicon.ico` 404 request from the local server; no gameplay or rendering error was recorded.
## Evidence
All evidence is under `playtest-artifacts/campaign-boss-pass/final-build-20261004-150021873/`:
- `barren-caves-campaign-boss-route.json` — native overlay state, dead-boss record, navigation, party health, healing, and observed combat events.
- `results.json` — final build module list, profile, and run-level browser errors.
- `barren-caves-boss-arrival.png` — visible FULL DUNGEON CLEAR panel and Anglo 1/1 result.
- `roster-priest-knight-level-30.png`, `roster-compact-priest-knight-level-30.png`, `barren-caves-entrance.png`, `barren-caves-boss-route-25.png`, `barren-caves-boss-route-50.png`, and `barren-caves-boss-route-75.png` — roster/body/gear and dungeon visual checks.
+48
View File
@@ -0,0 +1,48 @@
# Barren Caves tank death investigation (2026-10-04)
This is historical incident analysis only. Barren Caves was not replayed. The current default for live dungeon diagnostics is Stormwind Stockade: Cellblock Rush (`bite-sized-stormwind-stockade`); record its run-selected boss. Use an explicitly requested full-source route only when the mechanic requires it.
## Evidence reviewed
- `playtest-artifacts/campaign-boss-pass/final-build-20261004-150021873/barren-caves-campaign-boss-route.json` and its screenshots. The captured build assets were `index-DHQInfBp.js` and `combatStore-Cx06rFzG.js`.
- `playtest-artifacts/campaign-boss-pass/final-build-20261004-150021873/results.json`.
- The earlier exploratory run at `playtest-artifacts/campaign-boss-pass/exploration-current-dist-20261004-144223345/failure.json` and `failure.png`.
- Current combat ownership in `src/game/partyRuntime.ts`, `src/game/partyAbilityAi.ts`, and `src/game/generated/romNativePeriodicDamageBindings.generated.json`.
- At the time of the final capture, `scripts/playtest-campaign-boss-pass.cjs` had a 16-entry heal-attempt limit in `stabilizeCampaignPack`. The Stockade migration now removes the arbitrary attempt-count ceiling and retains the 110-second encounter/deadline bounds; this note describes the older capture behavior.
Both captures show a normal campaign full clear: 13:36.9 in the final build and 10:45.8 in the earlier exploration. The character started as a level-30 RoM Priest/Knight and naturally reached level 36. Rorik was the only fallen party member; the player and three damage companions survived. The final artifact records 46,328.47 effective native healing across the route and `partyDeaths: ["Rorik"]`. The earlier results screen also shows Rorik at 0 HP. Its harness failure happened after the results overlay opened, when the harness tried to click a party frame.
The final run reached a full-clear overlay before the harness's separate boss handler ran. Treat the final route pack as a normal-play incident trace, not an isolated boss balance trial.
## Final encounter findings
The final recorded pack began at 15:12:49.086 and ended at 15:14:24.850. It ran through two Kobold targets and Anglo. In the captured harness version, it recorded exactly 16 healing inputs and then stopped entering the triage branch. Thirteen inputs produced positive healing events; three produced no healing event and no resource change. Eleven positive heals targeted Rorik for 6,365 total effective healing; one healed Veyra and one healed Caelan.
Rorik's last positive heal completed at 15:13:55.625, raising him from 2,488.69 to 3,284.69 HP out of 3,488.69. The 16th recorded healing input at 15:13:56.628 healed Caelan. There are no later Rorik healing events. The hard 16-input guard therefore suppressed further triage for the rest of this long combined trash-and-boss pack, even if another ally later crossed the 88% threshold.
The captured casts do not show range as the blocker. The player-to-Rorik distance at healing inputs reached 18.66 m; the bound Urgent Heal range was 25 m, and those casts resolved. Across the 181 samples (which stop before this pack), the maximum player-to-living-party separation was 12.52 m; the pack-end value was 15.56 m. A single line-of-sight rejection occurred earlier in the route at 13.48 m and a later heal resolved. No failed final-pack input records an explicit range or line-of-sight reason, but concurrent combat feedback overwrote the failure message, so those three no-event inputs cannot be classified. Cast waits for resolved Urgent Heal actions were about 1.1–1.3 seconds. The player finished with 3,643/3,747 Mana, so resource exhaustion is not supported by this trace.
## Blood Arrow self-damage
The combat log also shows the NPC tank activating Blood Arrow, ability `rom-scout-general-4` (source skill 490434). The generated RoM skill row describes a 30-second effect that reduces the user's HP by 3% every second to raise ranged physical attack. Its periodic binding uses component 500871, a one-second HP drain with `dotBase: -3`.
Rorik's own runtime actor applied the aura seven times at 15:00:46.945, 15:02:50.840, 15:04:51.240, 15:06:51.332, 15:09:22.430, 15:11:35.425, and 15:14:08.939. The event log records 17,022 total Blood Arrow self-damage across the route. The final application produced eight 105-HP ticks through 15:14:17.022. This is separate from the 9,013.69 effective damage from mobs in the final pack.
From Rorik's last healed state to the last observed combat event, the log contains 2,218.69 effective mob damage and 840 Blood Arrow self-damage. That leaves about 226 HP by arithmetic if the event and health snapshots are complete; the result endpoint instead reports 0 HP. The exact lethal transition is therefore unresolved.
## Limits and next ownership
The route has 181 periodic samples, but the last is at 15:12:47.140, before the final pack started. The trace contains no HP samples for the roughly 96-second final encounter, and the combat event stream ends at 15:14:17.526, 7.3 seconds before the results endpoint. The endpoint proves Rorik was down, but it does not supply the lethal timestamp or a continuous HP curve. Do not treat the event arithmetic as proof of the exact killing blow.
The evidence identifies two concrete confounders before any encounter tuning: the captured route harness stopped healing after 16 recorded inputs, and the Knight/Scout NPC rotation applied a 30-second, HP-draining Blood Arrow effect. The first belongs to `stabilizeCampaignPack` in `scripts/playtest-campaign-boss-pass.cjs`; the current Stockade migration removes its attempt-count ceiling and samples HP throughout pack handling. Existing encounter/deadline bounds still prevent an unbounded run. The second belongs to the companion ability and periodic-effect lifecycle in `src/game/partyRuntime.ts`, `src/game/partyAbilityAi.ts`, and `src/game/romNativePeriodicDamage.ts`. The Blood Arrow lifecycle is already under a focused follow-up. Do not change Anglo or dungeon damage from this evidence.
For the next live diagnostic, use Stockade. Capture party HP, player-to-ally distance, selected heal target, cast result, resource, and Blood Arrow aura/tick events throughout the full boss phase. Then compare incoming mob damage with effective healing after the NPC self-drain behavior and harness cap are isolated.
The subsequent verified-pair implementation now removes legacy idle drain for
Knight/Scout and Scout/Rogue and uses owner-local toggle/deactivation cooldown
and per-ranged-action costs. Focused native/compatibility player/NPC checks and
ordinary Stockade UI evidence are in
[the implementation](ROM_BLOOD_ARROW_TOGGLE_2026-10-04.md) and
[the live report](ROM_BLOOD_ARROW_STOCKADE_PLAYTEST_2026-10-04.md).
This correction does not fill the missing historical lethal sample or establish
an exact cause for Rorik's old death.
@@ -0,0 +1,59 @@
# Blood Arrow scaling source audit — 2026-10-04
## Result
The current Chronicles of Arcadia sources do not establish Blood Arrow's
damage bonus at skill level 80. Keep the imported 10% modifier as the existing
simulator value until current rank data or an explicit formula is available.
Do not derive the cap-80 value from the published level-105 tooltip.
## Current source evidence
- [Current Scout/Rogue skill list](https://chroniclesofarcadia.com/wiki/skills/list/2-3?locale=en)
identifies Scout General Blood Arrow as skill `490434`. Its tooltip shows
`+105`, says the skill's maximum level is 105, and reports a 104.5% ranged
damage increase at that rank. It also describes the 2% HP ranged-attack cost
and 10-second cooldown after deactivation.
- [Current Knight/Scout skill list](https://chroniclesofarcadia.com/wiki/skills/list/6-2?locale=en)
identifies Blood Arrow as the distinct skill `499924`. Its `+105` tooltip
likewise reports 104.5% ranged damage and a maximum skill level of 105; it
additionally reports 2% HP and 1% MP per offensive ranged-weapon skill, +5%
Light Damage, and +15% received healing.
These current pages provide one numeric endpoint per identity: skill level 105.
They expose no lower-rank points, rank table, progression formula, API payload,
or raw current CoA source record. The game's level-80 character cap does not
identify what Blood Arrow value belongs at that cap. One level-105 endpoint
cannot establish a level-80 value or curve.
## Local RuneWaker boundary
The checked-in `src/game/romPlayerCatalog.generated.json` maps the imported
Scout General row `490434` to `rom-scout-general-4`. It contains one rank,
learned at character level 12. Its source component `500871` has ability
modifier type 52 (`ranged-damage`) with value 10. The row also retains the old
30-second duration and 3% per-second HP loss. The exporter
`scripts/runewaker-pipeline/export-player-catalog.mjs` resolves these
`MagicCollect` / `MagicObject` records from the local RuneWaker client
snapshot. This is evidence for the legacy imported 10% value and its stale
behavior, not a current CoA lower-rank curve.
Current verified pair mapping is owner-scoped in code: Scout/Rogue uses CoA
source skill `490434`; Knight/Scout uses CoA source skill `499924`, which the
local imported row represents as `490434`. Other owners retain the local
legacy import. Since no current CoA level-80 curve is available, this audit
does not change the catalog's existing 10% ranged-damage modifier for any
owner.
## Evidence still needed
To replace the retained value safely, obtain at least one independently
verifiable current CoA rank point at or below level 80 plus enough matching
rank points or an explicit formula to determine the progression. The evidence
must distinguish Scout/Rogue `490434` from Knight/Scout `499924`, or explicitly
show that their rank curves are shared. A current raw source/API record is
preferred; historical RuneWaker data and the level-105 tooltip alone are
insufficient.
The direct official `/wiki/...?...locale=en` skill-list URLs above resolve.
The alternate `/en/wiki/...` path may fail and is not the citation used here.
@@ -0,0 +1,104 @@
# Stockade Blood Arrow targeted UI proof
Run `20261004-194732821` completed on the corrected final build in the full
Stormwind Stockade (`stormwind-stockade`). It used the normal download and
role-selection flow, with Boss Testing off and `gmTestMode` false. The parent
build passed TypeScript, Vite, asset audits, compression, and release-bundle
verification before capture. The playtest served all five expected frozen
chunks and 141 JavaScript asset responses with HTTP 200:
- `index-CpWq1F33.js`
- `GameRuntime-CSfKe7bD.js`
- `combatStore-D4Bif_EK.js`
- `PartyFrames-BDJ5ssyc.js`
- `romAbilityCatalog-Dh-3_mot.js`
## Fixtures and input
Both profiles were prepared through the character UI as level-30 RoM
characters before entering the dungeon. Telemetry was read-only. Dungeon entry,
ability binding, movement, target selection, casts, and right-click aura actions
used ordinary UI controls. No combat-time profile, gear, weapon, health, mana,
cooldown, or mob-health edits were made.
| Fixture | Profile identity | Roster |
| --- | --- | --- |
| Primary | `Bloodarrowks`, `character-3fc723a3-01f2-46d4-81cb-b48125217eec`, level 30 Knight/Scout, RoM | Exact native-five complement verified: Priest/Knight, Knight/Scout player, Rogue/Warrior, Scout/Rogue, Mage/Warlock. |
| HP-only | `Bloodarrowsr`, `character-7275636c-ebe2-4d7f-99b9-57f12fce34f9`, level 30 Scout/Rogue, RoM | Ordinary generated party: Knight/Scout, Priest/Knight, Rogue/Warrior and another Scout/Rogue. It duplicates the player's pairing and omits Mage/Warlock from the native-five complement; this composition gap remains open. |
Blood Arrow was discovered as `rom-scout-general-4` (DBC source 490434; the
Knight/Scout alias is 499924). The real in-game primary bindings recorded for
the Knight/Scout were face-bottom → Blood Arrow, face-left → Scout `Shot`
(`rom-scout-general-0`, DBC 490423), and face-top → Holy Shield. The Scout/Rogue
fixture had face-bottom → Blood Arrow, face-left → `Shot`, and face-top → Arrow
of Essence. The character/equipment panel showed supplied level-30 ranged gear
before combat.
The on-screen Blood Arrow tooltip labels it permanent and states that each
offensive ranged-weapon skill costs 2.0% HP and 1.0% MP. That verifies the
displayed rule; the live Knight/Scout sample below does not isolate those exact
amounts.
## Results
- **Indefinite toggle and idle:** Blood Arrow was active at entry. The harness
did not press its toggle while already active; it used the normal right-click
path to deactivate it, then activated it again after the cooldown. During the
separate 32.094-second Knight/Scout idle window, the aura remained active and
the sampled combat log contained no Blood Arrow self-damage event. Incoming
enemy damage and party healing were separately present in the sample.
- **Player cancellation and cooldown:** Right-clicking the player's Blood Arrow
buff removed the aura and set an approximately 9.9-second cooldown. Pressing
the bound action while it was recharging produced no Blood Arrow cast event,
left the aura absent, and showed “That ability is still recharging.” After
readiness, the ordinary bound action restored the aura; using the same toggle
again removed it. The final aura counts were 1 after reactivation and 0 after
reuse-deactivation.
- **Different-buff guard:** Right-clicking Holy Shield on Knight/Scout and Arrow
of Essence on Scout/Rogue preserved each owner's Blood Arrow aura. Both
checks passed using the actual buff UI.
- **NPC owner isolation:** The visible Caelan Scout/Rogue party-frame Blood
Arrow icon was right-clicked. Caelan (`party-damage-1-rom-scout`) lost only
its own aura and entered a 9.864-second cooldown. The before/after cooldown
maps show null for the healer, rogue, and mage both before and after; only
Caelan changed from null to a Blood Arrow cooldown. No player AutoShot timer
was added or simulated.
- **Knight/Scout ranged cast:** The ordinary `Shot` action was accepted against
a Stockade Defias inmate; the actual log contains both a `cast` and `damage`
event from `__player__` for `rom-scout-general-0`. The pre/post sample was
3420.955/3420.955 HP and 1315.028/1315.028 mana to 3206.955 HP and 1304.445
mana. This window also records a 146-effective incoming hit from creature
`creature-79046`; the HP delta therefore does not isolate Blood Arrow's cost.
The mana sample also spans natural resource updates. Neither raw delta is
claimed as the exact Blood Arrow cost.
- **Scout/Rogue HP-only cast:** The same accepted `Shot` cast recorded HP
2293.534 → 2247.534 (−46) with resource remaining 100 → 100 and no other
player-directed combat event in the captured cast window. The observed HP
change is consistent with the expected rounded 2% max-HP cost for this
HP-only fixture.
The live sample does not isolate a clean Knight/Scout per-cast HP amount, does
not expose a separately attributable NPC scheduled ranged-auto cost, and does
not test the level-70 rider. The live proof does not quantify the existing
hybrid damage modifier or its cap. These RoM fixtures remain targeted Needs
Testing diagnostics, not balance certification. The combat segment was bounded;
this report does not claim a full Stockade clear.
## Evidence
All screenshots and raw snapshots are in
[`playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821`](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/).
The full telemetry is in
[`results.json`](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/results.json);
the reusable run harness is [`playtest-stockade-blood-arrow.cjs`](../scripts/playtest-stockade-blood-arrow.cjs).
| UI state | Evidence |
| --- | --- |
| Level-30 rosters, Stockade picker/entry and supplied gear | [Knight/Scout roster](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/knight-scout-roster-level-30.png), [entry party](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/knight-scout-stockade-entrance-party.png), [Inventory & Equipment training-gear panel](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/knight-scout-body-and-gear.png), [Scout/Rogue roster](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/scout-rogue-roster-level-30.png) |
| Active aura, tooltip/cost text and different-buff preservation | [Knight/Scout Blood Arrow](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/knight-scout-blood-arrow-active.png), [buff tooltip with permanent state and displayed cost](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/knight-scout-blood-arrow-buff-context.png), [other-buff click result](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/knight-scout-after-other-buff-right-click.png), [Scout/Rogue other-buff click result](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/scout-rogue-after-other-buff-right-click.png) |
| >30-second idle and accepted ranged casts | [idle window](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/knight-scout-blood-arrow-idle-over-30-seconds.png), [Knight/Scout Shot](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/knight-scout-after-ranged-skill.png), [Scout/Rogue Shot](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/scout-rogue-after-ranged-skill.png) |
| Player and NPC cancellation/cooldown | [player cooldown](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/knight-scout-right-click-off-cooldown.png), [activation rejected during cooldown](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/knight-scout-cooldown-activation-rejected.png), [reactivated](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/knight-scout-reactivated-after-cooldown.png), [toggle reused to deactivate](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/knight-scout-reuse-deactivated.png), [NPC owner aura](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/knight-scout-npc-blood-arrow-owner-buff.png), [NPC owner cooldown](../playtest-artifacts/rom-blood-arrow-stockade/20261004-194732821/knight-scout-npc-blood-arrow-owner-off.png) |
The run recorded zero page errors and zero HTTP errors. Chromium logged one
non-blocking 404 for `/favicon.ico`; the expected game chunks were all served
successfully.
+25
View File
@@ -0,0 +1,25 @@
# Blood Arrow toggle and cost contract — 2026-10-04
## Source identity
The Scout/Rogue current skill row identifies Scout General **Blood Arrow** as source skill `490434`. The RuneWaker import binds that row to local ability `rom-scout-general-4`. The matching current class page is [Chronicles of Arcadia — Scout/Rogue skills](https://chroniclesofarcadia.com/en/wiki/skills/list/2-3). Knight/Scout **Blood Arrow** is a distinct current source row, `499924`, on the [Knight/Scout skill page](https://chroniclesofarcadia.com/wiki/skills/list/6-2?locale=en). Its passive `499923` and Joint Blow `490420` are separate skills. The Knight/Scout ranged-skill surcharge is not applied to Scout/Rogue.
The current verified rows describe Blood Arrow as a toggle: recasting it, or right-clicking its buff icon, turns it off and starts a 10-second cooldown for that owner. The local import’s old 30-second expiry and 3% max-HP-per-second drain came from the stale RuneWaker snapshot. The indefinite toggle and removal of the legacy periodic self-damage binding are scoped to the verified Scout/Rogue and Knight/Scout owners; other builds retain the legacy imported effect pending their own source reconciliation. Activation itself has no health, mana, or focus cost for the verified pairs.
## Runtime behavior
- Player and owned NPC buff instances are owner-local for the verified pairs. Recast and right-click deactivate only the owner's Blood Arrow, remove its rider, and set the ability ready time to 10 seconds later. The context menu accepts only the clicked Blood Arrow aura with matching owner source and target; right-clicking another self-owned buff leaves Blood Arrow active. The persistent NPC frame keeps this cancelable indefinite icon visible while continuing to filter other long-term clutter. Player Status already displays persistent auras, so its layout is unchanged. Unverified builds do not receive the new toggle/deactivation cooldown handling. Death, removal, and roster synchronization clear the aura and stale cooldown for its owner.
- The Knight/Scout source contract charges 2% of max HP and 1% of max MP once when an eligible offensive ranged-weapon skill cast commits. Ordinary Scout General skills and the pair’s own offensive elite rows are considered; Scout Primary-only rows, non-damage control abilities, Blood Arrow itself, melee abilities, and the ongoing Auto Shot mode are excluded. Joint Blow source skill `490420` is included by its source identity even though the local tooltip omits the ranged-weapon wording. An owner without enough resources cannot commit the skill.
- Scout/Rogue Blood Arrow charges 2% max HP per ranged attack and no additional mana. The runtime charges eligible damaging Scout Primary/General skill casts and each owned NPC ranged auto swing while its own aura is active. The NPC path skips the swing if its owner cannot afford the health cost. Knight/Scout plain auto attacks do not receive the skill surcharge.
- The aura’s existing ranged-damage effect is retained. The local rank-scaling model remains unverified at cap 80; this change does not invent or import a level-105 damage curve.
- Blood Punishment’s 15% received-healing and 5% Holy-damage riders remain attached to the active Blood Arrow aura and therefore end with it. There is no separate rider timer.
Player ordinary auto attacks and repeated Auto Shot are not currently simulated as ranged events, so there is no player auto-attack hook to charge. This implementation does not add a new player ranged auto-attack system; full Scout/Rogue parity for player auto attacks remains open.
The current source tooltips state percentage HP/MP costs without distinguishing current from maximum pools. The simulator uses maximum HP/MP and rounds each cost to whole points; that percentage basis is a local interpretation. The published +105 damage value is not extrapolated to the project's level-80 cap.
## Verification
npx vitest run src/game/romKnightScoutBloodPunishment.integration.test.ts src/ui/AuraStrip.test.ts src/ui/PlayerStatusPanel.test.ts src/ui/partyResurrection.test.ts passes all 32 tests. Coverage includes ROM and WoW player costs and no-idle-drain checks, owned Knight/Scout activation and affordability in both rulesets, player recast/cooldown, Blood Punishment lifetime, and an owned Scout/Rogue ranged auto swing that charges once, keeps party and actor health synchronized, and receives Blood Arrow's ranged damage modifier. It also checks rank-resolved toggle behavior for verified owners, unchanged legacy behavior for an unverified Scout/Warrior, rejection of another buff's right-click, and rendered visibility of an NPC's tagged indefinite aura while unrelated long-term buffs remain filtered.
No dungeon playtest was run in this slice. Routine live QA now uses Stormwind Stockade: Cellblock Rush (`bite-sized-stormwind-stockade`); record the boss selected from the run ID. Full-source Stockade campaigns require explicit selection. No Wailing Caverns route or test was added.
+51
View File
@@ -0,0 +1,51 @@
# Campaign boss-route playtest — 2026-10-04
> **Current QA policy (2026-10-05):** Routine live tests use Stormwind Stockade: Cellblock Rush (`bite-sized-stormwind-stockade`); record the boss selected from the run ID. Full-source Stockade campaigns require explicit route selection. The Wailing captures and commands in this dated report remain historical; follow [the current test policy](TEST_DUNGEON_POLICY.md) and root `AGENTS.md`. A new Wailing reproduction needs an explicit owner request.
## Scope and method
This pass extends ordinary campaign routes in Barren Caves and Wailing Caverns through their normal boss encounters. The scoped Playwright harness creates an isolated Priest through the UI, prepares the permitted level-30/Knight-secondary fixture before entry, enters the normal Dungeons picker as healer, and uses ordinary WASD, Tab, F1/F2, party-frame selection, learned bound abilities, and the visible resurrection control. Source navigation paths are movement guidance only. During the live campaign, game position, health, mana, cooldowns, combat targets, party positions, and dungeon results are read-only telemetry; no loot was taken and no level-cap or readiness setting was changed.
The final build was produced by the parent task after Killing Spree and native-combat implementation. Its asset names were `index-DHQInfBp.js`, `combatStore-Cx06rFzG.js`, `GameRuntime-D87YWi4Q.js`, `PartyFrames-5jlxKxxK.js`, `romAbilityCatalog-CHjYfHkT.js`, and `index-499eecpe.css`. Earlier route observations are explicitly labeled current-dist exploration and are not substituted for final-build verification.
## Barren Caves: final-build full clear
The final-build ordinary campaign run completed the dungeon. The native result screen reads **FULL DUNGEON CLEAR**, **Barren Caves complete**, **Anglo — Defeated**, and **Bosses defeated 1/1**; time to the final boss was **13:36.9**. The visual proof is [barren-caves-boss-arrival.png](../playtest-artifacts/campaign-boss-pass/final-build-20261004-150021873/barren-caves-boss-arrival.png), and the read-only route/result record is [barren-caves-campaign-boss-route.json](../playtest-artifacts/campaign-boss-pass/final-build-20261004-150021873/barren-caves-campaign-boss-route.json). Build assets observed by this route harness were `index-DHQInfBp.js`, `combatStore-Cx06rFzG.js`, `GameRuntime-D87YWi4Q.js`, and `PartyFrames-5jlxKxxK.js`.
The run followed normal source-geometry checkpoints for 697.18 m of the 717.47 m guide and verified 358 of 376 vertices. The final boss and party defeated the encounter before the next checkpoint, which opened the native results screen; the driver then stopped without crossing the overlay. The character advanced from level 30 to 36 through normal encounter experience. Rorik was dead at the result screen; the healer and the other three companions were alive. No loot or results-screen action was taken.
## Barren Caves: current-dist exploration clear
An ordinary, navigation-guided Barren Caves run advanced through the cave and reached the native dungeon-results screen. The screen states **FULL DUNGEON CLEAR**, **Barren Caves complete**, and **Anglo — Defeated** with **Bosses defeated 1/1**; it reports **10:45.8** to the final boss. The run had explored 625 m. The visible result screen is [failure.png](../playtest-artifacts/campaign-boss-pass/exploration-current-dist-20261004-144223345/failure.png); the captured page text and Playwright error are in [failure.json](../playtest-artifacts/campaign-boss-pass/exploration-current-dist-20261004-144223345/failure.json). The 25%, 50%, and 75% ordinary-traversal images are [route 25](../playtest-artifacts/campaign-boss-pass/exploration-current-dist-20261004-144223345/barren-caves-boss-route-25.png), [route 50](../playtest-artifacts/campaign-boss-pass/exploration-current-dist-20261004-144223345/barren-caves-boss-route-50.png), and [route 75](../playtest-artifacts/campaign-boss-pass/exploration-current-dist-20261004-144223345/barren-caves-boss-route-75.png). The normal profile and entry images are [roster](../playtest-artifacts/campaign-boss-pass/exploration-current-dist-20261004-144223345/roster-priest-knight-level-30.png) and [entrance](../playtest-artifacts/campaign-boss-pass/exploration-current-dist-20261004-144223345/barren-caves-entrance.png).
The harness process exited with a locator timeout after the game had opened the result overlay: a follow-up heal tried to click Caelan's party frame, and the overlay correctly intercepted it. That is a post-clear harness error; it does not negate the visible native clear result. Rorik was dead in the result-screen party snapshot, while the other three companions and the healer were alive. The run received normal combat experience and the character advanced to level 36. No result-screen button was clicked and no loot was collected.
This exploratory result is not a final-build clearance claim. A separate final-build rerun uses the corrected overlay guard and stricter navigation driver.
## Wailing Caverns: exploration and route-driver correction
The earlier current-dist source-guided attempt covered 539.9 m against a 432.4 m planned path and reached 107 of 120 coarse checkpoints. Between checkpoints 106 and 107 the player dropped from about y=-90 to y=-106, ended in Kresh's Grotto, and remained 46.3 m from Lady Anacondra. The party remained together and alive, but the boss was not reached and Vow was not attempted. [The endpoint image](../playtest-artifacts/campaign-boss-pass/exploration-current-dist-20261004-143155433/wailing-caverns-boss-arrival.png) shows the lower water channel below the intended upper route.
This result is classified as a route-driver divergence, not a demonstrated dungeon navigation defect. The earlier driver used 3.8 m checkpoint spacing, a 4.4 m acceptance radius, 850 ms movement pulses, and could skip a blocked nearby guide point. Those tolerances could cut narrow corners or cross a ledge. The scoped harness now preserves each source-path vertex, accepts a checkpoint only within 0.65 m, scales short ordinary-input pulses from observed movement speed, records a large live downward displacement, and stops instead of skipping a geometry or elevation point. A tight source-navigation path is required before the Wailing conclusion can be updated.
The current profile exposes Vow of Silence (DBC spell 490275) at level 30. The final campaign identity had Vow assigned through the in-game Ability Controls UI to the secondary R1 input (Shift+5); the final-build binding image is [wailing-caverns-vow-binding-ui.png](../playtest-artifacts/campaign-boss-pass/final-build-20261004-151549020/wailing-caverns-vow-binding-ui.png). The route did not press Vow. The separate live Boss Testing result is recorded below. The corrected pinned source says Lady's listed Fear/Horror immunity does not imply Silence or Interrupt immunity.
## Wailing Caverns: final-build route and Lady encounter
The strict final-build route reached Lady Anacondra's Lair through ordinary movement input. It covered 433.96 m in the game and 430.14 m from input-step measurements against a 432.42 m navigation guide, verifying all 284 source vertices in 505 movement steps. No route block, downward-drop stop, player death, or party death was recorded; the endpoint snapshot and screenshots show all five party members alive. The route images are [route 100](../playtest-artifacts/campaign-boss-pass/final-build-20261004-151549020/wailing-caverns-boss-route-100.png) and [arrival](../playtest-artifacts/campaign-boss-pass/final-build-20261004-151549020/wailing-caverns-boss-arrival.png). They show the party, equipped staff/bow/shield silhouettes, and live Deviate Guardians in the lair.
Lady Anacondra did spawn and fight during approach combat. The event stream records her source-scheduled `spell-9532` damage against the party. A normal player Rising Tide action selected `lady-anacondra-spawn` at 1791127452078 with 2,942 HP remaining. While that cast was resolving, captured party damage events landed for 346, 166, and 2,430 effective damage, totaling exactly the remaining 2,942 HP. The action then returned **“That target is already defeated.”** This confirms the first-boss fight and its defeat during route stabilization. No Vow input was attempted in this campaign run.
The captured JSON's endpoint-only `bossFight` classifier says `boss-not-reached-or-not-loaded`; Lady is absent from `sceneMobsAtEndpoint`. Earlier periodic snapshots showed her full HP but did not sample her death during the blocking pack handler. The absence-only classifier misses the selected-target error and matching combat sequence, so it is not used as defeat evidence. The run did not capture `dungeonRunStore` objective progress or open the native full-clear overlay, so Wailing Caverns full clear is **unverified**. After Lady, the listed objectives include Kresh, Lord Cobrahn, Lord Pythas, Skum, Lord Serpentis, Verdan the Everliving, and event-only Mutanus; these were not covered. The five nearby-pack records also have empty initial engagement and zero heals/damage, so their `pack-cleared` labels are invalid and are not credited as kills.
At the original clipped-camera reference position, the live route reached a nearby pose 5.18 m away. Held right-drag changed yaw by -0.378 rad; after release and a further unheld mouse move yaw changed by 0 rad. Pointer lock remained null throughout and player movement stayed under 0.001 m per probe. The three inspected images are [before drag](../playtest-artifacts/campaign-boss-pass/final-build-20261004-151549020/wailing-caverns-original-clipped-endpoint-before-right-drag.png), [after drag](../playtest-artifacts/campaign-boss-pass/final-build-20261004-151549020/wailing-caverns-original-clipped-endpoint-after-right-drag.png), and [after unheld move](../playtest-artifacts/campaign-boss-pass/final-build-20261004-151549020/wailing-caverns-original-clipped-endpoint-after-unheld-move.png). This reproduces camera input recovery at a nearby pose; it does not establish visibility from every cave angle. A second check at the Lady route endpoint also rotated by -0.378 rad and remained stable after release.
The route used final production assets `index-DHQInfBp.js`, `combatStore-Cx06rFzG.js`, `GameRuntime-D87YWi4Q.js`, and `PartyFrames-5jlxKxxK.js`. The full capture is [wailing-caverns-campaign-boss-route.json](../playtest-artifacts/campaign-boss-pass/final-build-20261004-151549020/wailing-caverns-campaign-boss-route.json). A follow-on harness edit now probes the loaded Zustand exports for read-only `dungeonRunStore` progress and records it when exposed. That addition was not exercised by this completed capture; the next route record must confirm whether the current bundle exposes that store to the harness.
## Separate pre-correction live Vow of Silence diagnostic
The normal Boss Testing run in [ROM_VOW_LIVE_FINAL_2026-10-04.md](ROM_VOW_LIVE_FINAL_2026-10-04.md) is separate from campaign coverage. A UI-bound Priest used Vow on Lady's actual scheduled `spell-9532` Lightning Bolt; the cast ended before its scheduled completion and an 8.4-second Silence status applied. Nature Thorns (`spell-8148`) nevertheless became active during that status window, so Vow's full spell suppression is not certified. Lady was defeated in that diagnostic and all five party members survived, but it is not evidence of a Wailing campaign clear. The report includes the cast-timeline screenshots, raw event details, and the precise silence-gating limitation.
That pre-correction result is preserved under `playtest-artifacts/vow-live-final/final-build-20261004-151736260/`. The parent subsequently corrects the source-driven silence selector and rebuilds. The independent replay in `final-build-20261004-153859692/` on `index-Cm7Olrd2.js` / `combatStore-1B4KOVhS.js` passes real Bolt cancellation, no nonphysical cast during the full 8,400-ms status, and natural Nature Bolt resumption 61 ms after expiry. Lady is defeated with five actors alive. This later counter check supersedes the suppression failure; it does not replace the campaign route's earlier asset set or certify a full Wailing clear.
The campaign harness and report use the final production assets without building or changing game runtime source. No loot was taken and no readiness or level-cap setting was changed.
@@ -0,0 +1,11 @@
# Dark Energy Strike runtime note
Dark Energy Strike (498599) is implemented for the exact RuneWaker Champion/Warlock pair. The generated catalog identifies it as a level-30 skill, key item 545955, with prerequisite 497958 and ordered components 621305, 621306, and 621307. Rune Siphon (498595), the reset target, is the same pair at level 20, key item 545953, prerequisite 497958. Runtime requires the matching learned Rune Siphon row before attempting its reset.
The source collection orders a physical packet (621305), a Darkness packet (621306), then a 15% random group containing the Rune Siphon reset handler (621307). The runtime retains the source's group boundary: group 0 must produce surviving, positive effective HP damage for the target to receive group 1 and for the cast-level reset roll to qualify. A failed Darkness packet does not undo that eligibility. A group-0 kill skips the later target packet but still qualifies the cast-level reset roll. The roll is made once per single-target cast and resets only the owner's Rune Siphon cooldown; companion execution updates both party and combat-actor cooldown mirrors.
The 621306 source row declares MagicType 5 (Darkness), but the generic local component translator classifies it as physical when EffectType is 1. The exact 498599 override corrects only this cast's ordered damage schools to physical then shadow while preserving the existing source-derived packet formulas and level scaling.
The source engine treats a nonzero Parry result as surviving group 0. The pure gate helper preserves that rule, and its test covers a positive-damage parry. The live combat result currently represents parry as a zero-damage, not-landed outcome, so player and companion integration cannot currently produce that eligible parry case. Live eligibility uses positive effective HP damage after absorbs; a fully absorbed packet, miss, dodge, block, or zero result does not unlock the Darkness packet or reset roll. No synthetic absorb event was added.
Focused regressions cover ordered packet schools, physical failure and full absorb, physical kill, Darkness failure after a valid physical packet, the 15% threshold, exact class/ability/learned gates, and player/companion cooldown ownership. The catalog's existing learner checks skill level/rank but does not enforce source prerequisites; that is a general teaching-system boundary and was not changed here.
@@ -0,0 +1,57 @@
# RoM Champion Remaining Mechanics Audit
**Audited:** 2026-10-02
**Source:** the local RuneWaker `Resource` snapshot used by the generated player catalog.
This audit separates source-backed facts from fields still missing for runtime work. The local `learnmagic.db`, `magiccollectobject.db`, `magicobject.db`, and `string_enus.db` hashes match the corresponding source hashes recorded in `src/game/romPlayerCatalog.generated.json`. A missing generated-catalog entry therefore does not establish that a skill is absent from the source.
> **Later source/runtime update:** The [Champion source follow-up](ROM_CHAMPION_SOURCE_FOLLOWUP_2026-10-02.md) closes the RuneWaker conditions previously listed as absent for rank-2 Forge/Chain Drive and Dark Energy Strike, and records Rune Pulse's one-second cast-start damage window. Those mechanics are implemented. Rank-1 Forge companion auto-attacks now have owner/expiry-qualified event eligibility; a fully absorbed hit does not proc, and a landed hit grants its own stack and Rage. Focused Forge, Champion, and party-runtime tests passed 74 tests across three files. The Curse transform, full Shield Form payload, and Rune Overload target execution remain open; the older sections below retain their first-pass evidence.
## Shield Form (498562): learnability verified; execution remains open
**Outcome: source learnability is verified.** The local `learnmagic.db` contains Champion primary skill 498562 at level 16 with key item/flag 546211 and no listed prerequisite. The catalog exporter at `scripts/runewaker-pipeline/export-player-catalog.mjs` filters ordinary skill rows to `keyItemId === 0`; the separate elite-pair mapping does not include this flag-gated acquisition. That explains the generated omission. It is not evidence that Shield Form lacks a player-learnable source row.
The acquisition script `F:/Projects/Runewaker/Resource/luascript/02584.lua` offers flag 546211 through NPC organization 120245 when the player's race is Dwarf (`DrawfRace == 2`), vocation is Champion (`job == 10`), quest 425071 is complete, and the flag is not already set; selecting the option sets the flag. `02641.lua` blocks Champion skill training when flag 546211 is absent. The current character catalog in `src/app/characterCatalog.ts` also permits Champion only for Dwarves. The source condition is therefore consistent with current race/class eligibility, but additionally contains quest and learned-flag state that the simulator does not model.
The acquisition system in this simulator is level-derived and has no quest/skill-flag state. If the project later represents the skill as level-unlocked, it must explicitly treat the quest and flag grant as abstracted acquisition; it must still require the existing Dwarf/Champion eligibility and level 16. Do not make it available to other races/classes or claim the exact quest grant is simulated.
**Runtime remains unimplemented.** The local tooltip describes a toggle that increases accuracy and converts Strength to Stamina. `02550.lua` confirms the toggle-on/off path through buff 621218 and updates related conversion buffs. It computes a conversion amount as `floor(base equipment Strength * (0.1 + skill rank * 0.014))`, reads additional rank values at `MagicPowerLv_SP+5` and `+11`, and adds/cancels several persistent buffs. The source links children 498517, 498540, 498714, 498753, and 850048 through buffs 621218, 621288, and 621426, but the child payloads do not fully describe their effects. The simulator also has no separate per-skill rank or acquisition state corresponding to these `MagicPowerLv_SP` values.
Before implementing the toggle, source work must resolve the hidden child payloads and the intended relationship between Champion skill rank and the three `MagicPowerLv_SP` lookups. If implementing within the current level-only acquisition abstraction, document that quest state is abstracted. The old backlog statement that no player-learnable source skill exists should be corrected to say that source learnability is verified while runtime semantics remain open.
## Forge rank 2 (498604): proc payload is partial
**Outcome: do not implement the secondary proc yet.** The learn row identifies Champion primary skill 498604 at level 22, with prerequisite 498535. Its source components install a five-minute normal-attack trigger through buff 621251, which invokes 498590 at `onAttackTrigger rate=100`. The local description says normal-attack hits can trigger the eight-second Forge effect 621252. That effect's chance is not present in the child payload; the parent's `rate=100` describes the 498590 trigger and cannot establish a 100% chance for 621252.
Component 621253 supplies modifier values 20 (modifier types 204 and 205), and the description associates the effect with increased Rune Pulse (498529) damage and making the next Curse instant. The source does not establish the 621252 proc probability, the precise Rune Pulse modifier interpretation, or which Curse spell/event receives the instant-cast change.
**Needed to close:** a source field or handler that specifies 621252's roll chance and qualifying attack event; authoritative interpretation of 621253's modifier types; and the exact Curse spell and instant-cast application/consumption behavior.
## Chain Drive (498535): source row exists, but its payload is empty
**Outcome: source confirms the skill and qualitative behavior only.** The local Champion primary learn row exists at level 22 with key item 0 and no listed prerequisites. Its `MagicCollect` row has no components. The description says that while Forge Effect is active, normal-attack hits have a chance to reset Rune Pulse (498529)'s cooldown and increase its damage; it also says the next Curse becomes instant.
The source does not give the reset chance, precise qualifying hit/event boundary, Rune Pulse damage amount/duration/scope, or the Curse spell and instant-cast payload. Do not reuse Forge rank-2 component 621253 as the Chain Drive payload without a source link establishing that relationship.
**Needed to close:** the missing source components, an authoritative server/script handler, or a corrected source definition that supplies the probability, trigger boundary, Rune Pulse damage parameters, and Curse mapping/consumption behavior.
## Dark Energy Strike (498599): direct hit is described; Rune Siphon proc chance is absent
**Outcome: keep the unsupported cooldown proc suppressed.** The local learn row is a Champion/Warlock elite skill at level 30, keyed by 545955 and requiring 497958. Its direct hostile strike has a 20 Rage cost and source damage components 621305 and 621306. Component 621307 is a MagicFunc 7 action associated with resetting Rune Siphon, but neither it nor the related source fields specify a proc probability or a qualifying event. The tooltip only says there is a chance to reset Rune Siphon.
**Needed to close:** the chance value and whether the roll occurs on cast, landed hit, or another event, plus any target/success conditions for the reset. Do not infer a guaranteed reset from the presence of action 621307.
## Rune Overload (498572): child timing and drain are known; target selection is not
**Outcome: retain the verified RuneWaker identity and do not schedule the autonomous child yet.** In the local source, 498572 is Rune Overload and 498571 is Remodeled Body. This audit does not revisit the completed identity/catalog correction and does not import the conflicting current CoA reused-ID mapping.
Component 621241 links hidden child 498574 as an `onTimeMagicId` with a one-second interval (`dotTime=1`) and a 15-Rage-per-second drain (`dotBase=-15`). Component 621243 supplies the source damage field `damagePower=-0.6`, and the tooltip describes main-hand physical DPS damage to multiple targets in the immediate vicinity. The catalog now resolves the hidden child's 0.6 physical-damage coefficient from that component. The runtime has no autonomous timer consumer for this on-time child.
Neither the parent nor the hidden child's available target/effect fields specify a numeric radius, target-count cap, target-selection center/geometry, facing or line-of-sight rules, or whether each child tick applies once per eligible target. The source description “immediate vicinity” is insufficient to choose these values. Since the target set for each autonomous tick is unknown, the one-second proc path cannot be safely completed by supplying timing alone.
**Needed to close:** RuneWaker-version source that defines the radius and cap (including whether uncapped), target center and geometry, relevant eligibility/line-of-sight rules, and per-tick hit behavior. Do not fill these from the later CoA skill rework or a heuristic.
## Scope and implementation decision
No runtime change is made by this audit. Shield Form's source learnability question is resolved, but its toggle and child effects remain incomplete. Forge rank 2, Chain Drive, and Dark Energy Strike each lack distinct proc semantics. Rune Overload has a verified one-second child link but still lacks the target-selection semantics required for player and companion execution. None of these remaining runtime gaps meets the source-completeness bar for a safe implementation from the currently available RuneWaker fields.
@@ -0,0 +1,52 @@
# RuneWaker Champion source follow-up — 2026-10-02
This follow-up checks the RuneWaker `Resource/data` snapshot against the local `SourceCodeVS2019` engine and Lua scripts. It does not use the later CoA interpretation of reused skill IDs. No runtime or source data was changed.
## Shield Form (498562): rank slots and toggle path are partly resolved
`JobSkillBaseStruct::SaveLvPos` is documented as the skill-level storage position in `SourceCodeVS2019/Libraries/Union/RoleData/ObjectStruct.h:4147`; the player-catalog exporter reads the matching `learnmagic.db` byte at `scripts/runewaker-pipeline/export-player-catalog.mjs:461`. In the RuneWaker Champion learn rows, Shield Form 498562 maps to slot 4, Runecraft - Fortify 498563 to slot 5, and Last Line of Defense 498539 to slot 11. Lua `02550.lua` reads `MagicPowerLv_SP+4`, `+5`, and `+11` for those respective skills.
The self-targeted 498562 collection applies 621218 first. That MagicObject has `CheckUseLua=Lua_Job10_Skill1_Check`; the handler in `Resource/luascript/02550.lua` calculates the state when 621218 is absent. It converts base Strength using `floor(base Strength * (0.1 + Shield Form rank * 0.014))`, splits the result into buffs 621216/621217, applies 621222 using the Fortify rank, and applies 621228 when Last Line of Defense rank is positive. When 621218 is already present, the same handler cancels the conversion buffs and 621218, then returns false. `MagicProcess.cpp:1517` invokes a component's `CheckUseLua`, and `CheckUseLuaProc` removes the target when the handler returns false (`:5496`), giving the skill a source-backed toggle path.
The 621218 row also stores `OnTimeMagic_Magic=498517`, an interval of 3 seconds, and timeout child 498753. MagicCollect 498517 stores `Lua_Job10_Skill1_State` in its `LUAScript` field. The available server tree serializes these fields but has no execution use site for `MagicCollect.LUAScript`, `OnTimeMagic_Magic`, or `OnTimeMagic_Time`; that recurring refresh path is therefore not established here. The remaining Shield Form collection rows also contain unresolved payloads: 498562 groups 621218, 621288, and a self-skill check for skill 498715 leading to 621426; 498540 references 621229; 498714 conditionally references 621431; 498753 references 621289; and 850048 references 621244. The toggle's complete runtime effect is still not source-complete.
## Forge / Chain Drive: attack proc and Rune Pulse bonus are source-backed; Curse is not
MagicObject 621251 carries an on-attack trigger at rate 100 for MagicCollect 498590, lasts 300 seconds, and shares `clearFlags=1024` with rank-one Forge aura 621167. The engine dispatches mid-gear on-attack magic after the normal main- or off-hand hit when remaining `Damage != 0` (`Global_SimpleSchedular.cpp:789, 813-843`); the 100 rate therefore makes the 498590 trigger certain at that point, not the child effect. MagicCollect 498590 is self-targeted and uses Normal group processing. The rank-two 498604 is the level-22 upgrade rank of Forge 498523 with Chain Drive 498535 as prerequisite; it is not a separately learned base ability.
The groups also carry rank-two behavior outside the conditional branch: group 0 applies 621168's Forge stack on each qualifying trigger, and group 2 applies 621169's Rage restoration after group 1. Preserve that order so a failed Chain Drive roll still keeps the stack and Rage effects.
Its group 1 entries are ordered and must remain separate:
- 80% `Self_Buff` check for buff 621218, followed by MagicObject 621252.
- 30% `Rand` check, followed by MagicObject 621252.
The engine maps condition types to `Check_MyBuff` and `Check_Rand` (`MagicProcess.cpp:51-60`); both use `rand() % 100 < chance`, and the buff check first requires the exact buff ID (`:4905, 5143`). It also skips a target already marked `IsSpellOneMagic`; that marker is reset at the start of each group (`:1396`) and set after an effect attempt (`:2932-55`). Thus the second entry is a fallback for targets the first entry did not process, not an independent roll to combine into a derived overall chance. The first branch is specifically conditioned on the source Shield Form buff 621218; no rank or other inferred Shield Form state is involved.
MagicObject 621252 is an eight-second self effect with `EndUseLua=Cl_ArtisanSkill_621252`. The `Magic01_Assist` path first resolves `AssistMagic`, then invokes `EndUseLua` for each result before classifying misses or no-effect results (`MagicProcess.cpp:3876-4123`). It is therefore an effect-use/application callback, not a buff-expiry callback; the callback can still run for a no-effect result. The Lua handler resets Rune Pulse 498529, and also 498726 when the owner's sub-job is 3 (`Resource/luascript/02545.lua:361-369`).
Rune Pulse 498529's pre-use `CheckUseScript` is `cl_ChackBuff_498535` (`magiccollectobject.db` row 498529), and its catalog cast time is two seconds. `MagicProcess::SpellBegin` invokes the script before cast scheduling (`MagicProcess.cpp:187-210`). It checks for 621252 or the separate alternate buff 622185 and, when either is present, adds 621253 for one second; otherwise it still permits the cast. MagicObject 621253 contains modifiers 204=20 and 205=20. The source enum names these `AttackPlayerPowerRate` and `AttackNPCPowerRate` (`ObjectStruct.h:1646-47`); `RoleAttr.cpp:1823` applies percentage rate as `OrgSpeed * (1 + AddSpeed/100)`, and both physical and magical damage paths multiply through these outgoing rates (`MagicProcess.cpp:3614-16, 3840-42`). The source-supported effect is therefore +20% outgoing power against either player or NPC targets while the one-second buff is active. The modifier is role-wide in the engine; Rune Pulse is the cast whose pre-use script grants it, but the DB modifier itself is not restricted to that one spell.
621252 also stores `settingFlags=524387`, whose bit 19 (`524288`) is `MagicSpellFlagStruct::DisableShowMagicInfo` (`ObjectStruct.h:1392`). The source consumers found for that field only suppress client effect display (`rolesprite.cpp:5476`, `NetCli_MagicChild.cpp:651, 805, 955`); they do not change cast timing. Thus the one-second bonus begins at Rune Pulse cast acceptance and expires before its two-second impact. 498726 is reset by the 621252 callback for sub-job 3, but has no matching `CheckUseScript`, so it does not receive the 621253 bonus from that path.
The exact next-Curse spell and instant-cast transform/consumption remain unidentified. The 621252 callback only resets cooldowns, and the Rune Pulse script only applies 621253. The available Champion collection rows and scripts provide no bound Curse MagicObject or cast-time handler, so that tooltip rider must remain unwired.
## Dark Energy Strike (498599): Rune Siphon reset has a sourced 15% post-hit gate
The RuneWaker 498599 collection is single-target enemy, has `MagicSpellGroupType_Vampire1`, and has these ordered groups in `magiccollectobject.db`:
- Group 0: MagicObject 621305, physical calculation, damage power -0.7.
- Group 1: MagicObject 621306, Darkness magic calculation, damage power -70 with skill-level argument 1.
- Group 2: Rand 15, then MagicObject 621307.
For Vampire1, the engine enables erase-on-failure only for group 0 and applies the child in group 2 to the owner only if a group-0 target remains non-deleted (`MagicProcess.cpp:1426-30, 1489-1513, 1545-63`). In group 0, `Magic00_AddHP` deletes the target for Absorb, NoEffect, Miss, ShieldBlock, Dodge, or zero result value (`:2932-55`). A nonzero result such as Normal, Critical, or Parry survives; a parry remains eligible because it carries nonzero damage. Group 1 runs only for that surviving target, but its failure does not erase the target because erase-on-failure is off for later groups. Therefore the proc gate is the physical group-0 packet's surviving nonzero result; the later Darkness packet cannot turn that gate into a hit-or-both-packets requirement.
Group 2 then replaces the surviving target list with the owner and runs the 15% Rand check once for this single-target cast. MagicObject 621307 has `CheckUseLua=cl_ArtisanSkill_498599`; `CheckUseLuaProc` only calls the handler for a HIT target (`MagicProcess.cpp:5496-5512`), and Lua `02545.lua:114-118` resets Rune Siphon 498595. This supports a 15% Rune Siphon reset after a group-0 nonzero, non-blocked/non-absorbed result, not a guaranteed reset and not a roll on a miss, full absorb, block, dodge, or zero-value result.
## Remaining source gaps and implementation boundary
The Forge attack trigger, unconditional stack/Rage behavior, ordered 80%-conditioned/30%-fallback application, eight-second 621252 effect and cooldown callback, and the one-second role-wide 621253 modifier are implemented for player and companion actors. Rank-one and rank-two Forge use a shared exclusivity group, matching their common source clear flag. The simulator now grants 621253 when the cast is accepted and preserves its one-second expiry; the focused runtime test checks +20% while active and no bonus at the two-second impact. Keep the next-Curse rider unwired until a specific RuneWaker skill and cast-time handler are found. Dark Energy Strike's ordered physical/dark packets and post-physical-result 15% reset gate are source-backed as described above; the separate runtime work is owned by the Dark Energy change.
Focused validation passed: `npx vitest run src/game/romChampionForgeRuntime.test.ts src/game/romChampionRuntime.test.ts` (25 tests), including ordered roll, failed-roll stack/Rage, positive/zero/absorbed packet, rank upgrade, scoped cooldown reset, and Rune Pulse timing/damage cases. The default-memory `npx tsc -b --pretty false` check exhausted Node's 4 GB heap before reporting diagnostics; the repository owner is running the final aggregate TypeScript/release validation after concurrent edits freeze.
Shield Form still lacks complete hidden-child and recurring-state execution semantics. Rune Overload still lacks sourced target center, area geometry/radius, cap, eligibility/LOS, and per-tick target behavior as recorded in `ROM_CHAMPION_REMAINING_MECHANICS_AUDIT.md`; no new dispatch evidence closed that gap in this pass.
+34
View File
@@ -0,0 +1,34 @@
# RoM Mage/Druid: Current CoA Green Guardian
## Source choice and identity
This note covers only Mage-primary/Druid-secondary (`rom-mage` / `rom-druid`) skill `494331`. The current [CoA Mage/Druid skills page](https://chroniclesofarcadia.com/en/wiki/skills/list/4-8) identifies Green Guardian as a level-25 instant self skill. The exact pair and skill ID match, so this current CoA entry replaces the conflicting generated RuneWaker interpretation for that pair.
The generated `rom-mage-rom-druid-elite-30` row uses the same ID and name as a level-30 passive. Its RuneWaker components describe healing after Mother Earth's Protection ends. The local old hook in `combatStore.ts` only schedules those HoTs when it finds the passive Green Guardian row and its tagged Protection aura. The current Mage/Druid catalog row is now active, its translated effect is replaced with the stack aura, and the passive lookup therefore does not fire. This removes the old expiry HoT only for this exact pair; the RuneWaker passive and HoTs are retained for any other row using that source ID.
## Implemented behavior
CoA states that each second standing still grants one stack, capped at 20, and each stack adds one percentage point of movement speed. Movement pauses stack generation but does not say that it removes stacks. The runtime implements those explicit values and leaves MP restoration disabled: the page mentions a restore on stack loss, but does not identify the loss trigger or whether its 10% basis is maximum or missing MP.
The small timing rule needed by the simulator is explicit: after a sampled position change, the actor must accumulate one full stationary second before another stack can be gained. This is a one-full-stationary-second gate, not a claim about the source's unspecified “brief” pause duration. It does not decay or remove stacks.
## Runtime integration
- `src/game/romAbilityCatalog.ts` updates the existing exact-pair row in place: level 25, active instant self skill, no cost or cooldown, current CoA tooltip, and the existing generated ID. The reverse Druid/Mage pair gate remains separate.
- `src/game/romDruidOverrides.ts` replaces only the Mage/Druid 494331 effect with the current self aura. Other Druid rows retain their existing RuneWaker effects.
- `src/game/combatStore.ts` starts the caster aura at zero stacks, samples player and companion positions each combat tick, advances standing time, adds stacks to 20, and drops timing state after the aura is gone. The existing Mother Earth's Protection expiry branch is bypassed for this pair because 494331 is no longer a passive and has no legacy Green Guardian tag.
- `src/game/partyRuntime.ts` selects learned 494331 for an exact-pair companion on its first available combat action when the aura is absent, then uses the ordinary ability commit and effect execution path. CoA describes the skill as active but does not specify companion AI; auto-use in combat is a simulator policy, not a sourced mechanic.
- `src/scene/PlayerRig.tsx` applies the stack movement multiplier to the player. `src/scene/PartyPopulation.tsx` applies it to a Mage/Druid companion. Both scene hooks check the exact pair.
- `src/game/romMageDruidGreenGuardianRuntime.ts` contains the pair gate, stack cap, one-second transition, speed multiplier, aura definition, and timing helper.
The aura is indefinite and starts with zero stacks. The timer begins on the first movement sample after application; the simulator does not guess elapsed standing time before it can observe a position. Player accrual/movement coverage is in `src/game/romMageDruidGreenGuardian.integration.test.ts`; companion AI cast selection and aura application are covered in `src/game/romMageDruidGreenGuardian.party.integration.test.ts`. Helper and catalog regressions are in `src/game/romMageDruidGreenGuardianRuntime.test.ts` and `src/game/romDruidMageCoaCatalog.test.ts`.
## Still unknown
- The exact duration and refresh behavior of the movement pause.
- Whether any event removes stacks, and if so how many and at what interval.
- The MP percentage basis and whether each lost stack has a separate restore.
- Whether standing time counts during casts or other actions. The runtime observes position only.
- Any level-scaling formula beyond the stated per-stack values and 20-stack cap.
Historical [11.1.1.2000-2009](https://chroniclesofarcadia.com/patch/11-1-1-2000) and [11.1.6.1000](https://chroniclesofarcadia.com/patch/11-1-6-1000) patch notes describe Subterraneous Blade thresholds, not Green Guardian's pause or stack-loss rules. They do not fill these gaps.
+32
View File
@@ -0,0 +1,32 @@
# RoM Druid/Mage: Current CoA Inspiration
## Source choice and identity
This profile is limited to the Druid-primary/Mage-secondary pair and passive ID 494322. The current [CoA Druid/Mage page](https://chroniclesofarcadia.com/en/wiki/skills/list/8-4) lists `Inspiration` under Druid/Mage at level 30 with the same ID and name as the local RuneWaker passive, so this is a matching skill identity rather than an ID-only cross-pair guess. The current CoA mechanic replaces the conflicting local RuneWaker trigger.
The generated RuneWaker row has no components and says a Fireball hit has a chance to make the next spell cast in under one second. Current CoA instead says spending Nature's Power inspires nearby raid members. [Patch 11.1.5.3000](https://chroniclesofarcadia.com/patch/11-1-5-3000) specifies the reworked event and payload: each Nature's Power spend grants an Inspiration stack that gives 2% physical attack speed and 2% cast speed, stacks up to ten, and lasts ten seconds. At ten stacks the modeled bonus is +20% to each stat.
## Runtime behavior and simulator choices
- The pure helper in `src/game/romDruidMageInspirationRuntime.ts` represents one stack for each positive Nature's Power spend event, regardless of amount, with a 0–10 cap and +2 percentage points per stack. The player and generated-companion combat paths now invoke it after a successful positive Nature's Power cost or an actual caster-target Nature's Power drain. A partial/empty drain grants no stack; spending multiple points in one event still grants one stack.
- The passive is deterministic on a qualifying spend under the current CoA text. The older RuneWaker Fireball proc chance is not carried forward in the current tooltip or helper.
- The current CoA page lists `Range: 50` and says “raid members around.” The simulator cannot represent a raid, so runtime covers the player and modeled party members only. Existing CoA range conversion maps source units 10:1 to simulator units (for example, 150 to 15); applying that same convention makes this a 5-unit party radius. The page does not say whether the listed range is centered on the passive owner, so a caster-centered radius is an explicit simulator interpretation. The modeled check uses inclusive 3D distance, includes the living caster, and excludes dead or unplaced allies.
- CoA states a 10-second duration but not whether each stack has an independent timer or the entire stack aura refreshes together. Runtime uses the existing refreshable stack-aura model: each qualifying spend adds one stack and refreshes the shared aura's 10-second duration. This preserves the sourced cap and duration without inventing per-stack expiry timestamps.
- Each stack contributes +2% physical attack speed and +2% spell haste, up to +20%. The simulator separates melee and ranged haste, so the physical clause writes to both haste stats; this lets Hunter ranged swings and other physical autoattacks use the same CoA bonus. Spell haste reaches cast durations and GCDs. The Mage player's older generic aura reader skips this tagged Inspiration aura because the new shared haste path already includes it; this avoids applying spell haste twice to a Mage recipient. Existing unrelated haste sources continue to combine through their current haste paths.
- CoA also says this passive speeds up Fireball and restores one Nature's Power. The official-source audit for those separate clauses is below; neither clause is wired in runtime.
### Inspiration's separate Fireball clauses: official-source audit
- The [current CoA Druid/Mage skill page](https://chroniclesofarcadia.com/en/wiki/skills/list/8-4) lists Fireball under `Mage General`, level 30, ID `499943`, as an instant 6-second-cooldown spell. Its tooltip describes `3010 + 0.3 x Wisdom` Fire damage and one Nature's Power restored. The same page describes Inspiration as making Fireball travel “a lot quicker” and recovering one Nature's Power.
- The local [generated RuneWaker catalog](../src/game/romPlayerCatalog.generated.json) has `rom-mage-general-0`, general Mage Fireball ID `490204`, unlocked at level 4; its generated description references fixed damage scaled from INT. Both rows are Mage General Fireballs with the same name. The [11.1.5.4000 patch notes](https://chroniclesofarcadia.com/patch/11-1-5-4000) say Druid/Mage Fireball's fixed damage changed from Intelligence to Wisdom, which strongly supports `499943` being the current CoA counterpart of the local Fireball. However, the official sources reviewed do not explicitly state that IDs `499943` and `490204` are aliases or that one replaces the other. Conclusion: likely same intended action, but not formally established by an ID mapping; preserve the ID discrepancy in any implementation note.
- The official [10.4.1.1003 patch notes](https://chroniclesofarcadia.com/patch/10-4-1-1000) say Inspiration was changed to make Fireball travel faster “additionally.” This confirms a qualitative travel-speed rider existed, but gives no percentage, formula, or exact Fireball row ID. The current page still gives only the qualitative phrase “a lot quicker.” The official [11.1.5.4000 patch notes](https://chroniclesofarcadia.com/patch/11-1-5-4000) later changed Fireball's fixed-damage scaling from Intelligence to Wisdom in the Druid/Mage section, but likewise do not identify its row ID or quantify projectile speed.
- The official [11.1.5.3000 patch notes](https://chroniclesofarcadia.com/patch/11-1-5-3000) say Druid/Mage Fireball was changed to grant one Nature's Power additionally. The Fireball row's own tooltip also states that it restores one point, while Inspiration's tooltip separately says it recovers one point. The sources reviewed do not clarify whether Inspiration adds a second point or describes the Fireball grant, nor whether the point is granted on use, projectile launch, hit, or successful damage. The separate Inspiration change in the 10.4.1.1003 notes says it had a one-second delay; that does not establish the resource grant timing.
- Conclusion: CoA supports the qualitative travel-speed rider and a one-point Nature's Power grant associated with Druid/Mage Fireball. The current row, local row, and patch-history stat change make `499943` a likely counterpart to local `490204`, but do not formally map those IDs. Sources give no numeric speed effect, no event timing for the point, and no resolution of whether Inspiration's wording is an additional point. Do not infer these details.
## Catalog and runtime integration
The catalog overrides the existing generated passive row only when it is `rom-druid` / `rom-mage` ID 494322. It preserves that row's ID and learn level, clears the conflicting translated legacy effect payload, and uses the current CoA description on both the passive and its rank. No new ability row was added. Catalog regressions verify this exact-pair gating, existing-row identity, empty legacy effects/costs, and current tooltip text.
Player casts in `src/game/combatStore.ts` and generated-companion casts in `src/game/partyRuntime.ts` check for the learned exact-pair passive and apply one stack to living party actors in the interpreted radius. They listen to both committed direct Nature's Power costs and successful caster-target resource drains, since RuneWaker Druid skills commonly spend the resource through an effect instead of a cast-cost field. `src/game/romDruidMageInspirationRuntime.ts` owns the shared ten-stack aura and recipient geometry. The existing player and party haste consumers now read its melee- and spell-haste modifiers.
Focused validation: six helper tests cover exact-pair gating, one stack per spend event, cap, refresh, melee/ranged/spell stat payloads, and radius; three catalog tests cover current CoA identity and tooltip; three player/companion integration tests cover actual Nature's Power spends, nearby-recipient filtering, and cast-speed application without applying the bonus twice to a Mage recipient. Autoattack timing uses the existing shared melee/ranged haste stat paths; no separate weapon model was introduced for this passive.
+40
View File
@@ -0,0 +1,40 @@
# RuneWaker Druid Remaining Proc Audit
Updated 2026-10-02. This audit covers the seven unresolved Druid-pair passives named in the mechanics backlog and the Recovery identity conflict. It does not change runtime behavior or shared audit/backlog documents.
> **Later source update:** The bounded [Druid source follow-up](ROM_DRUID_SOURCE_FOLLOWUP_2026-10-02.md) supersedes the earlier “chance absent” findings for Revival Slash 499496 (Rand 25 after original-target survival), learned Spring Flower child 499935 (Rand 30 +1 Nature Power and a 1/3/5% expiry-heal chain), and learned Inspiration Display child 499942 (ordered 60%-gated effect/30% fallback and timeout payload). The remaining healing formulas still lack verified native runtime inputs; no automatic public-Inspiration or Spiritual-Gush trigger is established. The table below preserves the first-pass audit context.
## Source method
The local baseline is the RuneWaker `Resource/data/magiccollectobject.db`, `magicobject.db`, and `learnmagic.db`, with linked functions in `Resource/luascript`. The player-catalog exporter reads component records but does not serialize `MagicRunPlot.PlotName` (`scripts/runewaker-pipeline/export-player-catalog.mjs`, `componentFor`); raw `magicobject.db` records carry the plot name at `+0x284..+0x2c3`. Therefore a generated row with no exported plot name does not show that a source script is absent. A script is treated as linked only when the raw component graph names it.
The numeric proc chances for the RuneWaker passives below were not present in their passive `MagicCollect` records or in the linked Lua examined. A chance statement in a tooltip confirms a random trigger, but not its probability. Current CoA values are recorded as later-version identities/reworks; they are not substituted into the RuneWaker baseline.
The Avalanche CoA rework is deterministic, but current source leaves its defense school and any caster-side Nature's Power grant unspecified. The current local Rockslide path resolves its zero-cast-time effects synchronously, so it does not already represent the CoA two-second first impact. A current-CoA implementation needs a delayed impact event before applying the debuff at the sourced time; do not schedule invented timestamps for the three extra hits.
## Per-skill findings
| RuneWaker skill and local behavior | Raw local source finding | Current CoA evidence and identity | Result |
| --- | --- | --- | --- |
| **Warrior/Druid Revival Slash — 499496** (level 60): a hit by hidden skill 499497 may give the caster a reduced Recover effect, blocked while Recover is active. | Passive 499496 and child 499497 are present in `learnmagic.db`. Child 499497 component 623008 links to `Cl_JOB1_8_Heal_Decapitate` in `Resource/luascript/02707.lua`; that function self-casts hidden skill 499883 using the secondary-job Magic Power level. Its hidden effect uses components 623339/623340, whose source power/base values are 30/15 versus ordinary Recover 503796/503797 values 40/20. This supplies a concrete reduced healing payload, but no chance roll/value. The script casts 499883, not public skill ID 493528, so preserve that distinction. | Later CoA patch history changes Slash to a 25% Rage-restoration proc and later renames Revival Slash to Battle Lust. Those are later-version behavior and do not quantify this local Recover proc. [Patch 10.2.1](https://chroniclesofarcadia.com/patch/10-2-1-1000); [patch 10.4.0](https://chroniclesofarcadia.com/patch/10-4-0-4000). | The local trigger and reduced hidden heal are source-backed; proc probability and exact trigger-roll semantics remain unresolved. Do not import the 25% Rage proc. |
| **Rogue/Druid Quick Light Protection — 494924** (level 50): reduces Blind Spot energy cost by 10 and may heal the lowest-HP party member when striking a target. | Passive record has no MagicObject components and no linked plot. Local Blind Spot 490311 components 620282/620297 have no plot-name hooks. No raw linked source gives chance, heal amount, recipient tie-break, or whether the hit must land. | Current CoA keeps Quick Light Protection at level 50 but assigns it ID 494923; current ID 494924 is Malicious Intent. The current tooltip retains the −10 energy and chance-to-heal-lowest-HP-party behavior, without a chance or heal value. [Rogue/Druid skill list](https://chroniclesofarcadia.com/wiki/skills/list/3-8?locale=en). | Same-name behavior is recognizable, but the ID reuse is explicit. Keep local 494924 identity for RuneWaker; do not change the proc chance or rename the generated local row from current CoA alone. |
| **Mage/Druid Boiling Rock — 494565** (level 40): increases Magma Blade Fire critical rate and gives its Earth damage a chance to restore MP. | Passive has no components or linked plot. Magma Blade 494564 has local components 620227/620228 but no plot-name hook. The passive does not expose a chance or MP-restoration amount. | Current CoA reuses 494565 but reworks it: Subterraneous Blade inflicts damage twice at maximum Green Guardian stacks, and wand Magical Damage increases by 75%. Current Green Guardian has a 20-stack cap; Subterraneous Blade also describes an extra hit above 15 stacks. [Mage/Druid skill list](https://chroniclesofarcadia.com/en/wiki/skills/list/4-8). | This is a later rework, not evidence for the local proc. At the maximum 20 stacks, the active skill's >15 extra hit overlaps the passive's “damage twice” clause; do not add another hit without resolving total hit count. The wand bonus is explicit but is outside the requested local proc and should be source-qualified if implemented. |
| **Druid/Mage Inspiration Display — 499941** (level 70): hidden child 499942 can also trigger Inspiration, with a chance to double the triggered effect during Spiritual Gush 494370. | Passive 499941 has no components. Child 499942 is in `learnmagic.db`; its component 503999 links to `lua_star_Skill_NatureBase(0, 1)` in `Resource/luascript/01465.lua`, a deterministic one-point Nature's Power addition. The linked function does not implement a random Inspiration trigger or doubling. Other components do not name a proc plot. | Current CoA reworks Inspiration Display to enhance Earth Arrow with additional Fire damage. The current Druid/Mage page shows the newer Earth Arrow behavior; historical patch 10.2.1 supplies an older level-104 extra-damage figure, while patch 12.1.4 later reworks/renames Earth Arrow. [Druid/Mage skill list](https://chroniclesofarcadia.com/en/wiki/skills/list/8-4); [patch 10.2.1](https://chroniclesofarcadia.com/patch/10-2-1-1000); [patch 12.1.4](https://chroniclesofarcadia.com/patch/12-1-4-1500). | Local doubling chance and size remain unknown. Do not borrow the old patch value as a current rank curve. This is the level-70 **Inspiration Display 499941**, distinct from Druid/Mage **Inspiration 494322** already handled elsewhere. |
| **Druid/Warden Avalanche — 494029** (level 20): local Rockslide gains extra Earth damage and may restore one Nature's Power. | Passive record has no components or linked plot. Local Rockslide 493543 has components 503812/503823 and tooltip-linked damage component 503824, but none names a proc script. No local chance value or extra-damage payload link is present. | Current CoA keeps passive ID 494029 but reworks it to make Rockslide apply Weakening Seed. Current CoA Rockslide is ID 494063. Current Weakening Seed 493546 publishes an 18.8% generic defense reduction for 20 seconds at +105; Avalanche names one Rockslide target. Current Rockslide +105 applies its first damage after 2 seconds and also has three extra Earth damage events, whose individual timing is not specified. [Druid/Warden skill list](https://chroniclesofarcadia.com/en/wiki/skills/list/8-7). | The deterministic CoA rework is source-backed, but it is not a fully specified runtime contract. Existing RuneWaker Weakening Seed components 503815/620458 are each 20-second −2% magical-defense effects (`type 170`, translated to `magical-defense`); they do not reduce physical armor. Keep this local effect distinct from CoA's +105 18.8% generic “defenses” value. The +105 value is fixed for a current-CoA profile; the skill is published as max level 105, and the project has no lower-rank curve, so do not interpolate or substitute a +55 value. Current CoA says “defenses” without naming the school, so applying the local magical-only scope to the CoA value would be an explicit assumption. The passive names one target and gives no area behavior. It should apply once at Rockslide impact; CoA lists the first hit at 2 seconds, but not the extra-hit cadence. The current local zero-cast-time 493543 effect resolves synchronously at cast completion; `AbilityEffect` has no impact-delay field, so it does not represent the CoA two-second first-hit delay. Also unresolved: whether passive application includes the active Weakening Seed's one-point Nature's Power restore. Do not add extra damage or a resource grant. A future current-CoA implementation would need pair-qualified edits in `src/game/romDruidOverrides.ts` and `src/game/romAbilityCatalog.ts`, a narrow helper such as `src/game/romDruidWardenAvalancheRuntime.ts`, plus player/companion delayed-impact support in `src/game/combatStore.ts` and `src/game/partyRuntime.ts` if no reusable impact event exists, with focused catalog/player/companion tests. Keep current CoA Rockslide 494063 versus local 493543 explicit; this does not complete the RuneWaker proc. |
| **Druid/Warden Extended Recovery — 494200** (level 25): adds six seconds to Recover and may restore one Nature's Power. | Passive has no components or linked plot. Runtime currently adds three two-second Recover ticks (six seconds) behind the passive tag; the separate Nature's Power proc probability is absent. See `src/game/romDruidOverrides.ts` cases 494200 and 493528. | Current CoA reuses 494200 as **Recovery Expert**: Recover becomes HoT-only, affects raid members around the caster, may restore Nature's Power, and requires Nature's Power to cast. The tooltip gives no proc probability, pulse-level roll, radius number, or recipient rule beyond “raid members around.” Current CoA Recover is 493528. [Druid/Warden skill list](https://chroniclesofarcadia.com/en/wiki/skills/list/8-7). | The six-second RuneWaker behavior is source-backed and implemented; its chance remains open. Current Recovery Expert is a same-ID later rework, not the local Extended Recovery contract. Any mode switch must update the catalog, cast target/effect construction, and both player and companion execution together; do not infer a per-tick chance or radius. |
| **Druid/Scout Spring Flower Eulogy — 494932** (level 50): when casting 499935, target HP below 50% gives three stacks; the passive may restore one Nature's Power and adds healing when the flower ends. | Passive has no components or linked plot. Active 499935 component 505742 links to deterministic `lua_star_Skill_NatureBase(0, 1)`; this establishes a one-point Nature's Power addition on that active child, not the passive's separately worded chance. `Lua_Skill499935_main` in `Resource/luascript/02708.lua` contains an HP threshold branch, but no raw component PlotName points to it, so it is not accepted as a bound RuneWaker hook. | Current CoA retains 494932 and the below-50%/three-stack and Nature's Power chance clauses, while Camellia Flower is now 499954. Current CoA also describes an extra heal on expiration and Warm Spring cooldown reduction; patch 11.1.5.3000 sets the cooldown reduction to 3 seconds. Neither the page nor patch gives the Nature's Power chance. [Druid/Scout skill list](https://chroniclesofarcadia.com/wiki/skills/list/8-2?locale=en); [patch 11.1.5.3000](https://chroniclesofarcadia.com/patch/11-1-5-3000). | The HP threshold and three-stack branch are explicit; chance and the local extra-heal amount are not recovered from the bound RuneWaker graph. The current Warm Spring cooldown rider is a CoA-only rework detail unless current-CoA behavior is selected. |
## Recovery identity decision
There are two Druid/Warden behaviors attached to ID 494200. RuneWaker names it Extended Recovery and says Recover lasts six seconds longer; the active runtime applies exactly three additional two-second ticks. Current CoA calls the same ID Recovery Expert and changes Recover's targeting and payload. Current CoA Recover remains ID 493528, while RuneWaker's baseline Recover is also 493528. Keep the versions separate: the current page does not establish the local proc chance, the aura pulse at which it rolls, or a numeric party radius. This finding is unrelated to Warrior/Druid Recovery of Life/Rage of Calmness.
## Raw hook cross-check
- `export-player-catalog.mjs` includes component IDs and parsed trigger fields, but not the raw `MagicRunPlot.PlotName`; inspect `magicobject.db` records when the generated row lists no components.
- Linked Revival Slash child 499497 uses component 623008 and `Cl_JOB1_8_Heal_Decapitate`; that script casts hidden 499883 on its owner. The child payload components are 623339/623340. No roll percentage is encoded in the function.
- Druid/Mage child 499942 component 503999 and Druid/Scout skill 499935 component 505742 both bind the deterministic NatureBase +1 function. The separate random claims are not implemented by that function.
- The similarly named 499935 HP-threshold function in 02708.lua is not bound by a raw plot-name reference in the inspected source graph; do not treat a same-file function name as proof of execution.
## Sources
Local RuneWaker records: `../Runewaker/Resource/data/{learnmagic.db,magiccollectobject.db,magicobject.db}` and `../Runewaker/Resource/luascript/{01465.lua,02707.lua,02708.lua}`. Current CoA links are placed by mechanic above. CoA data supports documenting current identities and reworks; it does not fill the missing RuneWaker random chances.
+27
View File
@@ -0,0 +1,27 @@
# RoM Druid/Rogue: Current CoA Mechanics
## Scope and source choice
The profile applies only to the `rom-druid` / `rom-rogue` pair and CoA skill IDs 494321 (Necrotic Wound), 494024 (Corrosive Poison), and 494023 (Sinister Request). RuneWaker assigns different effects to these local IDs, so this profile replaces the conflicting RuneWaker effects instead of combining them. The [current English CoA Druid/Rogue skills page](https://chroniclesofarcadia.com/wiki/skills/list/8-3?locale=en) supplies current names and tooltip values; patch notes resolve values the current page leaves stale or vague. This is a RoM feature, so no WotLKDB data is used.
## Necrotic Wound and Corrosive Poison
- CoA requires Corrosive Poison on the selected target and one Nature's Power. Wound costs 4% MP, channels for 1.5 seconds, hits three times for 329.7% Dark damage per hit, spreads Corrosive Poison, and has no cooldown.
- [Patch 10.4.0.4000](https://chroniclesofarcadia.com/patch/10-4-0-4000) removed Wound's cooldown. [Patch 11.1.2.1000](https://chroniclesofarcadia.com/patch/11-1-2-1000) set three hits; [11.1.5.2000](https://chroniclesofarcadia.com/patch/11-1-5-2000) set the 1.5-second channel, 4% MP cost, and cooldown rider; [11.1.5.3000](https://chroniclesofarcadia.com/patch/11-1-5-3000) and [11.1.6.2000](https://chroniclesofarcadia.com/patch/11-1-6-2000) reduced its damage to the current 329.7% and made Nature's Power consumption once per cast.
- CoA's published range/radius values are 150/80. The project maps these source distances by dividing by ten, yielding range 15 and target-centered radius 8. The channel uses three evenly spaced pulses at 500 ms intervals; CoA specifies hit count and total duration but not individual pulse timestamps. The scheduler spaces pulses across the actual cast duration and retains Penance's immediate first pulse. The focused channel suite passes all six tests, including accelerated Penance.
- A successful cast hits enemies within radius 8 of the selected target and applies a fresh 12-second Corrosive Poison to each hit target. CoA specifies that poison spreads but not whether it copies remaining duration; refreshing the full duration is the simulator's explicit approximation. No target cap or per-extra-target damage falloff is added because [patch 12.1.0.5000](https://chroniclesofarcadia.com/patch/12-1-0-5000) removed Wound's prior 8% falloff. The simulator does not apply CoA's separate global 50% area-damage multiplier, so this profile does not invent a Wound-specific substitute.
- Corrosive Poison costs 25 Energy, has a one-second cooldown, and deals 11,342 Dark damage each second for 12 seconds at +105. The [English page](https://chroniclesofarcadia.com/wiki/skills/list/8-3?locale=en) and English patch history say 25 Energy; the [Japanese-localized page](https://chroniclesofarcadia.com/wiki/skills/list/8-3?locale=jp) says 25 MP. The English value is used and the locale discrepancy is kept visible. [Patch 12.1.0.5500](https://chroniclesofarcadia.com/patch/12-1-0-5000) supplies the 11,342 damage value.
- Each successful Wound cast reduces Sinister Request's remaining cooldown by one second. This rider comes from [patch 11.1.5.2000](https://chroniclesofarcadia.com/patch/11-1-5-2000); the helper cannot move readiness earlier than the current time. The channel's three synthetic hit events defer this rider, so it applies once when the channel completes instead of once per pulse.
- The Wound channel pays its 4% Mana and Nature's Power costs at channel start. Completion now checks only `costsToSpend`, which is empty for an already-paid channel; this prevents it from rechecking and rejecting the prepaid Nature's Power after it reaches zero. The player regression verifies payment once, three hits, spread to the primary and nearby targets, and no old root/healing-reduction effect.
## Sinister Request
- The current CoA tooltip restores MP, Rage, Focus, Energy, Psi, and Nature's Power for party members within radius 150 and lists no activation cost. This replaces the generated RuneWaker 494023 row's 15-Energy Speed Catalysis cost along with its old haste effect. [Patch 12.1.6.2004](https://chroniclesofarcadia.com/patch/12-1-6-2000) lowers the stale page cooldown from 20 to 15 seconds. The CoA page and [patch 11.1.5.2000](https://chroniclesofarcadia.com/patch/11-1-5-2000) also establish the one-second cooldown reductions from successful Poisonous Widow Embrace and Necrotic Wound casts.
- Runtime uses a party circle with radius 15 after the project's source-distance conversion. Its existing selector also requires a known position and line of sight; line of sight is a simulator constraint, not an extra CoA tooltip rule.
- Runtime fills only resource pools the recipient already has, caps each value at that pool's maximum, and records the refill against the caster and recipient. It does not synthesize missing pools. The player and companion paths are covered; companion AI selects the skill for a nearby living ally with a depleted supported pool even when the caster is full. A fully restored party or absent resource pool does not trigger that AI choice.
## Files and verification
- `romDruidRogueCurrentCoa.ts` holds the pair gate, values, tooltips, resource effects, and cooldown rider. `romAbilityCatalog.ts`, `romDruidOverrides.ts`, and `romCombatMechanics.ts` replace stale effects and enforce the poison prerequisite.
- `combatChannelAmounts.ts`, `combatStore.ts`, and `partyRuntime.ts` handle channel timing, player/companion poison spread, cooldown reduction, and resource restoration. `partyAbilityAi.ts` and `combatRotation.ts` provide the depleted-ally selector.
- Focused coverage: `romDruidRuntime.test.ts` (15 tests), `romDruidRogueCurrentCoa.test.ts`, `romDruidRogueSinisterRequest.test.ts`, `romDruidRogueSinisterRequest.integration.test.ts`, `partyAbilityAi.test.ts`, and `combatChannelAmounts.test.ts` (6 tests). The Sinister Request/catalog/AI run passed 29 tests across four files.
@@ -0,0 +1,76 @@
---
type: source-audit
project: healer-man
status: source-confirmed-partial
last_verified: 2026-10-02
tags:
- healer-man
- rom
- druid
- scout
- source-audit
---
# Druid/Scout 499935 NaturePower Rider
## Decision
The linked +1 Nature Power rider and its 30% source chance are confirmed for the Druid/Scout level-50 child 499935. This task records the source only. The generated player catalog currently includes passive 494932 but omits 499935, and the child's other bound healing effects cannot be computed from the stats available to the runtime without guessing. No learner, playable ability, or combat hook was added.
This is a child-ability rider, not evidence that passive 494932 has a known Nature Power proc chance. Keep 494932's separate HP-threshold and proc clauses open. The `Lua_Skill499935_main` function in `../Runewaker/Resource/luascript/02708.lua:125` contains a below-50% branch, but no 499935 `CheckUseScript` or linked component plot calls it; it is not a bound mechanic for this skill.
## Source identity and acquisition
The source `learnmagic.db` class-8 primary rows establish:
| Skill | Learn level | Key item | Prerequisite |
|---|---:|---:|---:|
| 494932 Spring Flower Eulogy | 50 | 543156 | 490420 |
| 499935 child | 50 | 543156 | 494932 |
`../Runewaker/Resource/luascript/02248.lua:164-166` maps Druid primary class 8 / Scout secondary class 2 to key item 543156 at the level-50 elite milestone. The existing generated row for 494932 confirms the parent passive is present; the child is absent because the exporter selects one `learnmagic.db` candidate per elite key item. Preserve 499935 as a separate learned row behind 494932 if catalog work resumes. Do not alias the child to another ability ID.
Source snapshot hashes for the relevant RuneWaker inputs:
| Source file | SHA-256 |
|---|---|
| `../Runewaker/Resource/data/learnmagic.db` | `6148199bcd1484ba1a122a6db5e2b3c2f2a161402bfe67fc67eb53f55fc6cfa3` |
| `../Runewaker/Resource/data/magiccollectobject.db` | `4aae19865cb07b30f99945aa7319a0096db244ff5e5b4b5d902fc6889474f501` |
| `../Runewaker/Resource/data/magicobject.db` | `52af13a2d8cfa9a66d4caa2d3c38832edc232f058995a64ef8135a6b82e43691` |
| `../Runewaker/Resource/luascript/02248.lua` | `ee9e337548abd7fc555d85bf2f96813dfd77416c3e65d4cadf74a80838da1486` |
| `../Runewaker/Resource/luascript/02708.lua` | `f9dda4ec4c1d86febab580ac0803b9d058ad6df887b4696b8ec86570244d067a` |
| `../Runewaker/Resource/luascript/01465.lua` | `074bbea5d3de4671423f6769dbd71d3696bc039edd60a4f2880605dce42fbe84` |
## Bound child effects
`MagicCollect` 499935 targets one selected friend (`RangeType=Target`) and uses `MagicSpellGroupType_Normal`. Its group 0 is an ordered target-buff ladder:
| Target already has | Group 0 applies |
|---|---|
| 623115 | 623115 |
| 623111 | 623115 |
| 623109 | 623111 |
| none of these | 623109 |
Each selected buff is a six-second Assist effect with one-second DoT ticks. Its raw base is 15 for 623109, 25 for 623111, and 35 for 623115; each has `DotSkillLVArg=16`. Their `OnTimeMagicID`s are 494952, 494953, and 494954. The three timeout collections apply fixed max-health healing of 1%, 3%, and 5%, respectively. The native timer runs the one-second DoT pulses and then queues the matching timeout effect once at expiration.
The periodic heal amount also depends on native `CalAddDotMagicLv` / `AssistMagic` calculations using MDMG, MND, HealPowerRate, HealPoint, MPow, and target healing absorption. Current `src/game/romStats.ts` models STR, STA, INT, WIS, AGI, HP, and Mana; `src/game/combatHealing.ts` resolves a supplied scalar amount. It does not expose the source inputs or full formula needed to represent these ticks accurately. The expiration percentages are known, but they do not complete the child healing envelope.
## Separate group-1 rider
`MagicCollect` 499935 group 1 slot 0 is `EM_MagicCheck_Rand` with value 30 and MagicObject 505742. Object 505742 is `MagicFunc=RunPlot` and names `lua_star_Skill_NatureBase(0,1)` from `../Runewaker/Resource/luascript/01465.lua:145`. The script adds one 503827 Nature Power stack to `OwnerID()` and normalizes the caster's own stack count. Its source cap is 10, with up to five extra points for Druid/Scout when flag 543146 is present.
The native `MagicProcessClass::Check_Rand` uses `rand() % 100 < RandValue` for each eligible target. In Normal group mode, group 1 runs independently of group 0. The selected-target range means this cast has one target candidate and one group-1 roll. `Magic07_RunPlot` dispatches the plot only for HIT or CRITICAL target results; it does not require a positive healing amount. Since `NatureBase` reads `OwnerID()`, the rider belongs to the caster even though the selected target is a friend.
This bound 30% child rider does not establish the separate 494932 passive's chance, the passive tooltip's below-50% threshold behavior, or any passive-owned expiration clause. Those remain unresolved. The child group-0 timeout heals above are separately visible source effects; they are not represented as a completed passive implementation.
## Future integration boundary
If a later task supplies or implements the missing periodic-heal inputs, keep the work narrowly scoped:
- Add the exact level-50 Druid/Scout 499935 learner in `scripts/runewaker-pipeline/export-player-catalog.mjs`, requiring key item 543156 and learned 494932.
- Suppress only an unconditional translation of component 505742. Preserve the 30% Rand check, Normal group execution, successful target-result phase, and one NaturePower grant to that cast owner, capped by that owner's pool.
- Preserve the group-0 tier ladder and its three expiration heals. Do not infer HP-threshold behavior from the unbound Lua helper or attach 494932's unknown passive chance to the child rider.
- Integrate player and generated-companion casts behind the exact learned child and pair in `src/game/romCombatMechanics.ts`, `src/game/combatStore.ts`, and `src/game/partyRuntime.ts`. Keep companion resource gains on the companion's own pool.
No exporter, catalog, runtime, or test changes were made for this note-only task.
@@ -0,0 +1,33 @@
# RuneWaker Druid Source Follow-up
Updated 2026-10-02. This is a read-only continuation of [the remaining-proc audit](ROM_DRUID_REMAINING_PROC_AUDIT.md). It follows native collection conditions, callback dispatch, and the corresponding LearnMagic rows. It does not repeat the prior PlotName graph audit or substitute later CoA identities. No runtime files were changed and no tests were run.
## Native dispatch findings
`MagicCollectCondition` stores a check function, component ID, and two arguments (`../Runewaker/SourceCodeVS2019/Libraries/Union/RoleData/ObjectStruct.h:4389-4393`). The source enum is Normal=0, FirstGroupHit=1, PrvGroupHit=2, Vampire=3, Vampire1=4 (`ObjectStruct.h:4412-4418`). In `magiccollectobject.db`, the mode int32 is at record `+0x2C8`: 499935 record `0x9C7304` has bytes `00 00 00 00`; 499497 record `0x958D54` has `01 00 00 00`; 499942 record `0x9C8F3C` has `03 00 00 00`. These offsets pin the mode independently of the condition rows. `Check_Rand` selects a surviving target when `rand() % 100 < RandValue` and skips deleted targets or targets already resolved in that group (`../Runewaker/SourceCodeVS2019/Server/NetGameServer/MainProc/MagicProc/MagicProcess.cpp:4905-4918`). The engine resets `IsSpellOneMagic` at each group, runs each condition in order, and dispatches its component after the check; group target transitions are handled in the same loop (`MagicProcess.cpp:1390-1534`). Therefore ordered 60/30 rows are not a combined-roll estimate.
`MagicBase.CheckUseLua` is called after the collection condition and before the component effect. The Lua guard only evaluates HIT targets; a false return removes that target from the pending effect list (`MagicProcess.cpp:5496-5518`). `EndUseLua` runs from effect handlers after the result is known. `MagicCollect.CheckUseScript` is a separate cast-use check (`MagicProcess.cpp:187-212, 935-962`). The targeted rows have no such collection script. The `MagicCollect.LUAScript` member is declared in `ObjectStruct.h:4489-4497`; no consumer for that field was found in the targeted NetGameServer source. The global Lua VM loader loads FDB or configured text scripts and calls `Initialize`; the split loader also loads `C:\Runewaker\Resource\luascript` (`../Runewaker/SourceCodeVS2019/Server/NetGameServer/MainProc/Global.cpp:219-285, 301-325`). `Magic07_RunPlot` dispatches a component's `RunPlot.PlotName` on HIT or CRITICAL (`MagicProcess.cpp:4719-4743`).
The raw event-trigger slots were checked on the linked Revival Slash components and the Inspiration child payloads. `623008` has `OnAttack` tuple `[10,0,0]` (rate with no trigger ID); its on-time, on-hit, timeout, rebound, and death IDs are zero. `623339` and `623340` likewise have no event IDs. The 499942 delay buffs are the exception: both carry `OnBuffTimeOutMagicID=494344`. Spring Flower's stack buffs carry a separate `OnTimeMagicID` expiry event, detailed below. `BuffProc` decrements the timer, applies periodic damage/healing ticks, then queues the timed magic at a matching remaining-time divisor before removing an expired buff (`../Runewaker/SourceCodeVS2019/Libraries/Union/RoleData/RD_ValueCal.cxx:3456-3470, 3607-3622`). Thus the numeric proc chances below come from collection Rand fields, not an inferred callback or plot-name convention.
## Source-backed candidate rows
| RuneWaker mechanic | Exact local evidence | Status for runtime work |
| --- | --- | --- |
| **Warrior/Druid Revival Slash 499496 / hidden child 499497** | `learnmagic.db` has Warrior primary entry 128: 499496, level 60, key 546742, prerequisite 493528; general entry 28 is hidden 499497 with prerequisite 499496. Child 499497 is `FirstGroupHit` mode (raw record `0x958D54`, mode field `+0x2C8` = 1). Group 0 requires the original hostile target's hit to survive; misses/zero-value failures delete that target. Groups 1 and 2 retain the original target, with later hit types forced to HIT (`MagicProcess.cpp:1425-1459, 1544-1558, 2932-2954`). Group 2 is one `Rand 25 -> 623008` check. Its plot calls `Cl_JOB1_8_Heal_Decapitate`, which self-casts 499883 at secondary-job Magic Power level; the separate CheckUseLua only guards against active 623340 or Recover 503797 (`../Runewaker/Resource/luascript/02707.lua:43-58`). | **Chance resolved: 25%, once on the surviving original target per cast.** The hidden heal is not yet a complete runtime formula. Components 623339/623340 use HolyHeal base 30 and periodic base 15 (skill arguments 20/18); normal Recover 503796/503797 uses 40/20. Native HolyHeal also uses MND, MDMG, MPow, HealPowerRate, and HealPoint (`MagicProcess.cpp:2636-2655`). Do not scale ordinary Recover by 0.75. The current runtime has no targeted 499496/499497/499883 handler. |
| **Druid/Scout Spring Flower Eulogy 494932 / active 499935** | `learnmagic.db` Druid entry 71 is 499935, level 50, key 543156, prerequisite 494932; `02248.lua:164-166` maps Druid/Scout level 50 to key 543156. Its Normal group mode is 0 (raw record `0x9C7304`, mode field `+0x2C8`). Group 0 is an ordered target-buff ladder: 623115 if target has 623115, otherwise 623115 if it has 623111, otherwise 623111 if it has 623109, otherwise 623109. Group 1 is `Rand 30 -> 505742`; 505742 binds `lua_star_Skill_NatureBase(0, 1)` in `01465.lua:145`, granting one Nature Power. The similarly named `Lua_Skill499935_main` function in `02708.lua:125-143` is not bound to the inspected component. | **Proc chance and expiration effect resolved:** 30% for +1 Nature Power on learned/cast 499935, plus a bound 1/3/5% maximum-HP end heal. The stack buffs have six-second duration (`EffectTime_SkillLVArg=0`) and one-second Dot cadence, with bases 15/25/35 and DotSkillLVArg 16; native tick scaling depends on MDMG, MND, HealPowerRate, HealPoint, MPow, and target healing absorption (`RD_Normal.cxx:2423-2501`). Each tier's OnTimeMagic is scheduled at interval six: 623109 -> collection 494952 -> component 505706 (FixPer HP 1); 623111 -> 494953 -> 505740 (FixPer HP 3); 623115 -> 494954 -> 505741 (FixPer HP 5). The final DoT tick and end heal occur when the six-second buff reaches zero. The below-50% Lua helper remains unbound. This is a source-backed candidate tied by LearnMagic prerequisite to 494932. The current generated player catalog has no 499935 row, so HealerMan has no invocation or runtime approximation for it yet. |
| **Druid/Mage Inspiration Display 499941 / hidden 499942** | `learnmagic.db` Druid entry 91 is 499942, level 70, key 546840, prerequisite 499941. Its `Vampire` group mode is 3 (raw record `0x9C8F3C`, mode field `+0x2C8`); the later group target redirects to the owner after an earlier target survives. Group 2 is ordered `Rand 60 -> 623123`, then `Rand 30 -> 504890`. A successful first assist marks the target resolved and suppresses the fallback. 623123 is gated by `lua_bico_dru_mag_es_70` checking Spiritual Gush buff 505163 (`02708.lua:154-161`); if that guard rejects the first effect, the second check can still run. Both one-second special buffs time out to collection 494344 (`../Runewaker/SourceCodeVS2019/Libraries/Union/RoleData/RD_ValueCal.cxx:3042-3070`), whose effect is component 504863: 10 seconds, modifier type 51 (`SpellSpeed_AllMagic`) at -1000 (`ObjectStruct.h:1427-1478`). | The hidden row and its learned prerequisite are source-backed. This establishes the child’s ordered 60% gated effect / 30% fallback and timeout payload. It does **not** establish an automatic cast from public Inspiration 494322 or an automatic trigger from Spiritual Gush 494370; 505163 is only the 623123 gate. Model it, if selected, as the 499942 variant with this exact order and payload. The current generated player catalog has no 499942 row. |
## Remaining unresolved mechanics
- **Quick Light Protection 494924:** its passive row has no component conditions; active Blind Spot 490311 has ordered SelfEqType checks but no Rand chance. The proc probability, heal amount, and recipient tie-break remain unknown.
- **Boiling Rock 494565:** its passive has no component conditions; active Magma Blade 494564 has no Rand condition. The MP-restoration chance and amount remain unknown.
- **Avalanche 494029:** its passive has no component conditions; Rockslide 493543 has no Rand condition. The local extra-damage and Nature Power proc payloads remain unbound.
- **Extended Recovery 494200:** neither its passive row nor Recover 493528 exposes a Rand condition. The existing runtime approximation at `src/game/romDruidOverrides.ts:162-163` adds six seconds; the separate Nature Power chance remains unknown.
- **Spring Flower Eulogy 494932:** its passive row has no group condition. The sourced 499935 Rand30 clause above is usable as the learned child mechanic; other passive clauses still have no bound numeric chance in the inspected rows.
These checks cover the named parents, active rows, learned hidden children, and linked effect objects only. RuneWaker remains separate from the later CoA reworks recorded in the original audit.
## Healing-input boundary
The RuneWaker stat enum identifies MND as stat type 5 (`ObjectStruct.h:1427-1434`), and the HealerMan exporter maps source stat type 5 to `wisdom` (`scripts/runewaker-pipeline/export-rom-heirloom-reference.mjs:23-27`); `src/game/romStats.ts:17-37` exposes that base value. This is a verified base-stat alias, but the targeted RoM combat path does not provide the final effective MND value consumed by the heal formulas. The direct HolyHeal formula also needs native MDMG, the cast's Magic Power level, MPow, HealPowerRate, HealPoint, and target HealAbsorbRate/HealAbsorb (`MagicProcess.cpp:2640-2674`). Periodic heal scaling uses the analogous caster values and target heal absorption through `CalAddDotMagicLv` (`../Runewaker/SourceCodeVS2019/Libraries/Union/RoleData/RD_Normal.cxx:2423-2501`). No verified RoM-runtime aliases were established here for those final values. Keep the Revival Slash heal and Spring Flower periodic tick amounts blocked until those mappings exist; the Spring Flower expiry percentages are separately source-defined.
+308
View File
@@ -0,0 +1,308 @@
# RoM dungeon texture, lighting, and route review — 2026-10-06
This continuation reviews all 30 base RoM dungeons. Luna subprocesses handled
source-material inspection, original lighting recovery, and independent runtime
review. Screenshots from an isolated asset camera establish visual coverage;
ordinary production UI and keyboard input establish entry and walking evidence.
Neither method certifies every corridor, a full clear, or combat balance.
## Texture and material changes
The all-dungeon room review covers 30 entrances, 66 boss anchors, 74 diagnostic
corridor samples, and 36 mapping-hotspot views. The corridor cameras are samples
between authored anchors, not proof of connected walking routes. Large low-rank
UV metrics require source/material attribution before applying repeat tiling:
waterfall sheets and flow effects must not be treated as stone floors.
Six dungeons had exact native `gate_waterfall` materials exported as opaque,
with the compressed image losing its alpha: Cave of the Water Dragon, Kulech
Bones Nest, Mystic Altar, Raksha Temple, Sardo Castle, and Tomb of Seven Heroes.
The source-pinned material patch covers 40 native bindings (38 normal blends,
two additive bindings). Native prelit metadata also retains its verified unlit
semantics. The JSON-only alpha patch retains identical BIN bytes. The subsequent
unlit semantics pass can repack BIN layout; a final decoded-layout proof verifies
identical positions, normals, indices, every UV stream, morph targets, node
hierarchy/transforms, and exact PNG image bytes across all six candidates.
Optimization disables simplification and automatic texture resizing; the KTX2
decode proof demonstrates retained partial alpha, not lossless codec equality.
Mystic Altar's reviewed support-floor texture remains part of the canonical
input and its metadata is preserved.
The durable converter reads native alpha parameters and exact diffuse-channel
joins. `lib/native-alpha-cache-validation.mjs` rejects old resource caches unless
source hashes, exporter/converter/alpha-policy hashes, and raw/prepared native
material reports agree. `stage-native-waterfall-alpha.mjs` produces guarded
review candidates; `promote-native-waterfall-alpha.mjs` verifies identities and
creates exclusive baseline backups before updating canonical/shipping assets
and their current hashes. Historical proofs remain historical.
The Lair of the Demon Dragon's `magic_magma_02` sheets had the same provenance
gap. All three exact source rows (2, 3, 9) are prelit cutouts, with native alpha
test value 192. They now retain MASK cutoff 192/255 and unlit semantics, replacing
the opaque black slab with the source orange flow strips. The 512×128 UASTC
image retains alpha 0–255; source and decoded image each have 37,654 pixels
passing `>192`. Mean alpha error is 0.000244, so codec equality is not claimed.
The final canonical proof preserves all geometry, UVs, hierarchy/transforms, and
all 17 exact source PNG images. These are native flow-effect sheets, not stone
floor atlas mappings, so no repeat tiling was guessed. Its stage, response-body
SHA checks, first-hit material proof and screenshots live in
`artifacts/playtest/rom-room-coverage/lair-magma-alpha-stage/`.
The six waterfall acceptance pairs require the exact target texture to be the
nearest ray hit in both shipping baseline and compressed candidate. The served
candidate identity and native BLEND provenance are verified. Four-metre Kulech
and Tomb pairs supply additional surroundings; Kulech's additive effect is very
bright and is not credited as a complete scene-quality pass. Early bounding-box
views and the first misrouted comparison are diagnostic failures, superseded by
`gate-waterfall-triangle-pairs-report.json` and
`gate-waterfall-context-pairs-report.json`. Synchronous camera scans explicitly
refresh the camera matrix before raycasting; otherwise they can inspect the
previous pose between rendered frames.
The final Barren policy replaces whole-atlas repeats with four exact 256×256
native floor islands. Only triangle corners contained in one reviewed island
receive the ×4 presentation UV1; source UV0, geometry and original atlas remain.
Its walls use a fifth exact 256×256 crop from the native central wall region at
[256,0], sampled at two metres with mirrored edges and rotated phase blending.
Wall base contrast is 0.25 around the source atlas mean, with detail strength
0.85; floor detail strength is zero. This explicit browser treatment reduces
oversized smearing and obvious tile repetition without generating replacement
pixels. The original 47,084 triangles and eight native PNG images are retained.
Its exact crop RGBA proofs are separate from lossy compressed-texture metrics.
HOTO keeps its native non-repeating cliff artwork and UV0. Its revised v2 policy
samples the original full stone/moss tiles directly at two metres on floor faces
of materials 26 and 18. Those floors use base strength 1 and modulation strength
0; material 18 samples its own moss tile. Cliff materials 96 and 53 retain their
base artwork, with floor/wall detail strength 0.85, wall contrast 0.6 around each
source atlas mean, and rotated detail variation 1. Material 26 retains wall
strength 0; material 18 retains 0.45. These settings correct presentation scale,
not native texture resolution. The v1-to-v2 patch changes only approved material
metadata; all non-JSON chunks remain byte-identical in canonical and optimized
GLBs. All 189,855 source triangles and 17 native PNG images are retained. Source-detail
carriers require joining/pruning protections during optimization. HOTO adds no
cropped images; its decoded source-layout proofs are separate from lossy
compressed-texture metrics. The fixed-camera compressed comparisons use verified served hashes and
report no browser errors. Evidence is under
`artifacts/playtest/rom-deep-review/uv-stretch-review/`.
The v2 continuation is promoted through `promote-hoto-surface-v2.mjs`, with a
new exclusive recovery backup and `hoto-surface-v2-promotion-proof.json`.
Shipping SHA-256 is `b80b60cba6e5a0eb3e13bd7e048f9408f21bf870c0c81fc8de5c195d3a3eaee3`.
The unique v2 screenshots have pinned hashes in `hoto-surface-v2-visual-proof.json`.
The earlier shared HOTO v1 final screenshot names were overwritten during the
v2 comparison and are explicitly marked unavailable in its stage/promotion
reports. Their historical asset hashes remain recorded; those image paths must
not be treated as preserved v1 captures. Earlier diagnostic captures remain
separate evidence. The current unique v2 proof supersedes that comparison.
## Source lighting and shadows
The native zone exporter recovers environment settings and oriented zone
triggers from all 30 source WDBs. Generated data retains source hashes, native
ambient/primary/two secondary colors and directions, fog, time/weather groups,
and priority/parent relationships. The resolver converts runtime positions back
into source space and follows native trigger selection and setting inheritance.
Time/weather groups default to 0/0; this does not implement a live weather clock.
`DungeonLighting.tsx` supplies these settings to production RoM environments.
Rune colors are linear byte/255 values. Rune's unoccluded SH constant band is
supplied as ambient fill (4/17 of the weighted directional colors), with the
complementary 13/17 in Three.js directionals. This preserves readability in
roofed rooms without adding a guessed white light. Three.js angular diffuse and
PBR specular remain an adaptation; the original separately authored specular
path and full SH shader are not reproduced. Standard's source-primary shadow
follows the player's footing; High follows the camera. Missing native zones use
the reviewed presentation profile. WoW uses its existing profile lighting path.
The final adapted-source entrance check covers all 30 dungeons: 29 native-zone
selections and Grafu Castle's entrance profile fallback, with zero browser
errors. The broader source-lighting camera review covers 96 entrance/boss
anchors, 95 native-zone selections and the same one fallback. Four same-camera
profile comparisons establish that SH fill keeps Forsaken Keeper 3 and Ystra's
Raichika room readable; source-dark Sardo and Kulech remain dark interiors.
Barren's pale source lighting retains rock/sand detail without clipped whites.
## Origin water
All 126 source water layers retain their native GUID joins, visibility,
vertex RGBA, source tile coordinates and 30-frame normal sequence. Metadata now
also retains the first source vertex's split-plane height and exact serialized
full-model enable flag. Raw effect value 4 keeps its original value and unknown
enum name; Rune's non-DIRECT full-enable branch establishes its rendering policy.
The browser reflects the camera across that native plane, clips below it, and
captures the pre-water scene for refraction. It uses Rune's shared projected UV,
0.025 bump perturbation, and 0.02037/0.97963 Fresnel coefficients. Per tagged
asset root, four active 512-pixel target pairs share at most ten two-pass
captures per second. Oldest-request scheduling avoids render-order starvation;
inactive pairs release their slots when a later plane needs them. Materials
dispose shared targets once. Additional active planes and below-plane views use
the lit animated fallback. Reflect-class filtering and the native water SH
shader remain unsupported. Water stays visual-only.
Same-camera final water captures record visible glancing reflections, zero
browser errors, and approximately 60 FPS. Metadata-only promotion preserves
both canonical and optimized BIN hashes. Original-source water colors remain
unchanged. Evidence: `artifacts/playtest/rom-deep-review/water-screen-effects/`.
## Walking evidence and remaining route issues
Before this lighting/material continuation, ordinary UI walking covered all 30
current source environments: 489 attempted legs, 487 reached, 882/882 grounded
samples, 1,010.312 m travelled, and zero browser errors. Twenty-eight planned
walks completed. Raksha's first forward probe blocked while grounded; Dalanis's
second waypoint exhausted the movement time budget while grounded. These are
retained failures, not successful clears. See
`artifacts/playtest/rom-deep-review/ordinary-walking-baseline/results.json`.
The complete Origin source review still finds no supported entry-to-Falynum
connection. Full 256-chunk terrain and current options-aware collision/navigation
leave the Falynum platform disconnected. Its visible ROS platform is 7.23 m
above the ground below, and the native path component is separate. The referenced
boss Lua teleport is a combat catch-up action after acquiring an attack target,
not an approach transport. No bridge or approach teleport was inferred. The
entry-to-Life connection remains in the current Recast navigation and ordinary
walking proof. Detailed verdict:
`artifacts/playtest/origin-route-diagnostic/origin-falynum-source-connectivity-verdict.md`.
## Evidence and validation
- Room cameras: `artifacts/playtest/rom-room-coverage/`.
- Compressed alpha candidates and guarded promotion:
`artifacts/playtest/rom-room-coverage/native-alpha-stage/`.
- Adapted lighting: `artifacts/playtest/rom-source-lighting-adapted-entry-qa/`;
comparisons: `artifacts/playtest/rom-source-lighting-profile-compare/`.
- Native lighting resolver, linear runtime colors, source shadow pose,
terrain/water materials, water resource lifecycle/scheduling, native alpha
cache/staging/converter semantics, source UV exceptions, and optimizer policy
have focused passing tests. TypeScript checks pass.
The pre-v2 reviewed build is `artifacts/playtest/rom-deep-review/build-reviewed-20261006/`.
Its frozen manifest is `reviewed-content-manifest-20261006.json`, version
`content-fcd09f7c0f8f10be`, SHA-256
`f1a7ab2dc9a3d05513f3601ed5142011f71aa58155a7ec1d34bdc42e4f9309af`.
TypeScript, Vite production build, static precompression and release-bundle
verification pass: 1,328 modules, 126 chunks and 5,569 bootstrap objects.
Its all-30 quality audit matches 1,620/1,620 images to source resolution,
including five exact pixel crops, with zero downsizing, 2048-cap hits or issues.
This audit skips general pixel decoding; targeted codec/alpha proofs described
above cover the changed material families. All 162 dungeon GLBs validate with
zero actionable errors/warnings. KTX2 audit covers 106 visual assets and 12,897
compressed images with zero fallbacks; the existing performance budgets have
zero regressions. Focused runtime tests pass 83/83 and focused pipeline tests
pass 17/17. No readiness promotion, full balance sweep, commit, or external
deployment is part of this review.
The refreshed v5 build is `artifacts/playtest/rom-deep-review/build-surface-v5-20261006/`,
with index SHA-256 `ab46b9c47a0ba27b0b1c2e0a2c65ff02c613b7b87c54d37fe5ec9a7a41707e27`.
Its frozen manifest is `surface-v5-content-manifest-20261006.json`, version
`content-d1ec6f1f858f21c1`, SHA-256
`e102c30cc47a4130fff88809ce53453929e86e6f766b0afbbae8a8ad4a52fd7c`.
TypeScript, production build, 129-source static precompression (258 outputs) and
release-bundle verification pass. It retains 126 chunks and 5,569 bootstrap
objects. The refreshed all-30 quality audit again matches 1,620/1,620 textures,
including five verified crops, with zero downsizing, cap hits or issues. All 162
dungeon GLBs validate with zero errors/warnings. Focused checks pass 83 runtime
and 17 pipeline tests. See `environment-quality-surface-v5-20261006.{json,md}`.
The v5 ordinary walking checks reached 48/48 legs across Barren (27), HOTO (2)
and Origin (19), with 89/89 grounded samples, 101.826 m travelled and zero errors.
HOTO remains a six-metre probe; Origin follows Life. Root inspected Barren leg 11,
HOTO leg 1 and Origin leg 18 High frames: corrected detail is present, bodies and
equipment render, and Origin's documented opaque root cards remain. Evidence is
in `production-targeted-routes-surface-v5-20261006/`. Stockade's v5 fallback
selected **Bazil Thredd**, passed default/High settings and recorded zero browser
errors; root inspected the High frame. Its evidence is in
`graphics-fallback-surface-v5-20261006/`.
The final v5 entry pass reaches all 30/30 registered dungeons with ready assets
and grounded players in both Standard and High (150% render scale, 16× filtering,
authored ambient). It records 60 screenshots and zero browser errors. Independent
and root contact-sheet review found no actionable new entry regression; the
documented Raksha/source-panel framing limits remain, and Kulech's maroon
obstruction did not recur. See `production-entry-surface-v5-20261006/`.
`validation-summary.json` independently checks the frozen build/manifest, all 30
unique dungeon IDs, settings, movement outcomes and the three changed visual
assets against both shipping files and immutable content objects.
The local `dist` now contains that reviewed build: all 5,967 files match byte for
byte. The previous build is preserved at `pre-surface-v5-dist-backup/`; installation
proof is `local-build-install-proof.json`. This is a local installation, not an
external deployment. Final release hygiene is recorded after note updates in
`release-check-final.log`.
The pre-v5 intermediate frozen production pass rendered all 30 entrances through the
normal UI, with ready assets and grounded players in both Standard and High,
60 screenshots, and zero browser errors. The eight changed material/water
environments also received ordinary keyboard walking: 150/151 legs reached,
277/277 grounded samples, 325.037 m travelled, and zero browser errors. Raksha's
blocked first leg is retained. Stockade's graphics fallback selected Hamhock and
passed default/High rendering checks. Evidence is under
`artifacts/playtest/rom-deep-review/production-entry-final/`,
`production-walking-final/`, and `graphics-fallback-final/`.
The pre-v2 targeted routes use the reviewed build and frozen manifest above:
Barren reached 27/27 legs, HOTO 2/2 and Origin 19/19. All 95 sampled positions
were grounded, with 103.622 m travelled and zero browser errors. HOTO remains
only a six-metre collision probe; Origin targets the connected Life route,
not Falynum. Standard/High walking frames are in
`production-targeted-routes-reviewed-20261006/`. That Stockade fallback
selected **Kam Deepfury** and passed default/High settings, with zero errors;
its evidence is in `graphics-fallback-reviewed-20261006/`.
The pre-v2 all-30 entry pass also reached ready, grounded entries in Standard
and High with 60 screenshots and zero browser errors. Visual review flagged
remaining HOTO scale issues, addressed by the v2 policy above. Barren retains
broad source-painted striations despite the corrected fine detail. Raksha's
entry camera clips inside architecture and its first route leg remains blocked;
this is not a complete scene-quality acceptance. Wider source-anchor views
provide separate material/lighting coverage. Kulech's High entry frame contained
a maroon obstruction during combat. It did not recur in 25 consecutive High
frames in an ordinary-UI follow-up. The original Standard/High pair compares
changing combat states, so exact object attribution remains unproven; no lighting
defect was demonstrated. Read-only rays in the clear frames identify the static
source wall/stone behind it. See `kulech-obstruction/findings.md` and `frames/`.
Those intermediate production screenshots found further issues even though the
historical pre-crop audit's 1,615 matched textures retained their dimensions. Resolution checks do
not establish good surface mapping. Barren's whole-atlas repeat mixes floor and
wall regions; restoring UV0 removes the added bands but leaves oversized detail.
The promoted atlas-safe floor/wall correction and HOTO source-detail policies
above supersede those intermediate mappings.
Origin's giant-tree family also retained alpha pixels but lacked native MASK on
six canonical materials merged into one optimized material. Its source-pinned
JSON-only correction is now promoted, preserving every non-JSON GLB chunk and
all terrain/water settings. Seven freshly exported ROS resources prove standard
lighting and MASK cutoff 192/255; cache/converter smoke passes all seven. The
same-camera 3.5 m leaf close-up has matching served hashes, exact first hits,
unchanged lighting and zero errors. A separate leg-18 diagnostic context uses
the recorded walking position, but is not itself ordinary input evidence.
The separate `elves_vine` card also lost cutout semantics and compressed alpha.
Fresh exports independently prove that `elves_vine.ros` material 1 and
`act_green_tower.ros` material 3 use the same DDS with standard lighting and
MASK cutoff 170/255. Both canonical bindings and their optimized merged material
now retain that policy. The replacement 256×256 UASTC image retains nine mip
levels and all 10,407 source pixels passing the cutoff, with zero threshold-mask
mismatches; alpha bytes are not claimed lossless. The canonical BIN is unchanged,
and the optimized patch preserves all non-target buffer views, mesh streams,
terrain and water metadata. Same-camera served-hash proof removes the black
vine panel with zero browser errors. Its exclusive backup and proof live under
`artifacts/playtest/rom-deep-review/origin-root-card-attribution/`.
The residual leg-18 card is `Object01_1_mesh_0_10`, native material 1 from
`gaint_tree_a.ros`, using `elves_gaint_roots_village`. Fresh source flags request
alpha test 192, but all eight native DXT1 mips, the prepared PNG, and all ten
shipping KTX mips are fully opaque. This is not a lost-alpha regression. The
exporter supplies neither vertex-color/alpha nor face-culling channels, so the
complete native behavior remains unverified. No black-keyed mask or forced
cutout was invented. The card remains a visual limitation, documented in
`origin-root-card-attribution/residual-roots-village/roots-village-alpha-proof.json`.
Evidence and exclusive promotion backup:
`artifacts/playtest/rom-deep-review/origin-tree-alpha/`.
Mystic's crimson entry panel is the source-authored opaque
`cowcowcowcow01_164_mesh_0`; the source atlas is entirely opaque. Sardo's close
column is the authored `channel_pillar_01_52_mesh_0`, likewise opaque. Sardo's
first ordinary walking leg opens the room; Mystic's panel still occupies much
of some walking frames, so those frames do not establish whole-room lighting.
The source-anchor camera review supplies wider material/lighting coverage.
Exact source identities and framing evidence are in
`production-entry-final/entry-framing-attribution.md` and its JSON companion.
+45
View File
@@ -0,0 +1,45 @@
# Native RoM five mechanics gap audit — 2026-10-04
## Scope and finding
This targeted audit covers the five active native identities in `src/game/romFiveIdentities.ts`: Knight/Scout Rorik, Priest/Knight Serenna, Rogue/Warrior Veyra, Scout/Rogue Caelan, and Mage/Warlock Durnik. It checks the current source inputs and translated effects that reach player and owned-NPC casts, including pair skills actually learnable in each selected build. RoM remains **Needs Testing**; this is not a readiness or balance promotion.
The native stat and combat-input route already contains the active-five source channels audited in the recent native passes, including HolyHeal and supported DotMagic healing, player/owned-NPC source bindings, training weapons, Throw, ShieldDef, native target resolution, and target-count falloff. This review found one concrete pair-effect mismatch: the Knight/Scout Blood Punishment rider still used RuneWaker's old 50% healing-received child and omitted current CoA's Light damage bonus. It now modifies the caster's existing Blood Arrow aura with current CoA's 15% healing-received and 5% Light/Holy damage benefits. No separate passive timer is created.
The owned-party direct-damage adapter also had two gaps that hid this rider in NPC play: it inferred native RoM damage school from presentation text, and its deterministic no-roll direct path did not resolve generic caster damage auras. The party path now uses `abilityDamageSchool` for Runewaker spells and prefers an explicit direct effect school when the translated source component supplies one; the ability-level school remains the fallback. This preserves source-described mixed packets without inferring from presentation text, while WoW school selection is unchanged. Active actor-owned damage modifiers are also applied to no-roll Runewaker direct hits. The dedicated Holy Blessing modifier is excluded from that generic pass because Priest already resolves it through its source-specific path. Native `statRuleset: "rom"` hits continue through the existing combat-roll resolver.
## Blood Punishment source and identity
The generated RuneWaker catalog identifies `499923` as the learnable level-70 Knight/Scout passive Blood Punishment, with raw prerequisite ID `490420` (Joint Blow, not Blood Arrow); the source general active is Scout Blood Arrow `490434`. Current CoA publishes the Knight/Scout class variant as `499924`. The local `learnmagic.db`, `magiccollectobject.db`, and `magicobject.db` SHA-256 values match the generated catalog's recorded hashes. Local component `623167` links its one-second `onTimeMagicId` to `499910` for 30 seconds. `Resource/luascript/02708.lua`'s `lua_bico_kni_sco_es_70_blood` checks owner buff `500871` and cancels `623167` when that Blood Arrow marker is absent; this is the old child-timer behavior.
The [current CoA Knight/Scout skill list](https://chroniclesofarcadia.com/wiki/skills/list/6-2?locale=ar) still identifies Blood Punishment as Knight/Scout `499923`, the Knight/Scout variant of Blood Arrow as `499924`, and says Blood Arrow increases received healing by 15% and Light damage by 5% while active. The [10.2.1 patch history](https://chroniclesofarcadia.com/ru/patch/10-2-1-1000) records the 15% healing-received reduction for Knight/Scout Blood Punishment. The passive identity and pairing match the local row, so the current CoA rider replaces the stale local 50%/30-second child. The current page's level-105 examples do not change Healer Man's level-80 cap.
The runtime attaches both modifiers directly to the existing caster aura tagged `rom-self-health-drain` for source skill `490434`. That keeps the rider actor-local and ties its lifetime to the active Blood Arrow aura already modeled by the simulator. The simulator still models the local Blood Arrow 30-second lifetime and 3%-of-maximum-HP periodic cost; this change does not claim full CoA toggle, deactivation cooldown, or per-ranged-skill HP/MP cost parity. The local 623167/499910 timer is intentionally not layered onto the current CoA rider.
### Blood Arrow base-contract work at the time of this pass
**Identity correction from the subsequent continuation:** CoA list `1-2` is Warrior/Scout, and its Blood Arrow `499998` must not be treated as the Scout general skill. Scout/Rogue list `2-3` identifies `490434`; Knight/Scout list `6-2` identifies its variant `499924`. The local prerequisite `490420` is Joint Blow. See `docs/ROM_BLOOD_ARROW_TOGGLE_2026-10-04.md` for the subsequent pair-aware toggle/cost work and its current limits. The paragraph below records the earlier pending base-contract state.
This is source-confirmed but intentionally not implemented by the passive-rider fix. The [current CoA Warrior/Scout skill page](https://chroniclesofarcadia.com/en/wiki/skills/list/1-2) documents Blood Arrow as a toggle that can be deactivated from its buff, with a ten-second cooldown on deactivation and an HP cost on physical attacks. The [10.7.0 patch notes](https://chroniclesofarcadia.com/en/patch/10-7-0-1000) also describe Blood Arrow's per-tick Mana cost. Healer Man's local `490434` instead remains a 30-second aura with a 3%-maximum-HP periodic drain and has no player toggle, deactivation cooldown, or per-offensive-attack HP/Mana charge. The Warrior/Scout page's Blood Arrow row is `499998`, while the Knight/Scout page identifies the passive's active as `499924`; this audit does not assume those rows have an identical current cost contract. Keep these base-skill differences open and do not describe the pair as fully CoA-parity complete.
## Other active identities
| Identity | Audit result |
|---|---|
| Priest/Knight | The selected pair rows and Devotion Halo are covered by the pair catalog/runtime checks, and the native healing bindings cover supported direct and periodic HolyHeal for player and owned-NPC casts. The source-only Holy Chains child has no measurable player-facing payload; no runtime value is inferred. No comparable source-confirmed player/NPC effect mismatch was found. |
| Rogue/Warrior | The selected pair effects are covered by the pair tests, including Throwing Mastery, Whirlwind Mastery, Poison Spray, Toxic Splash, and Poison Battle Technique. One-Hand Axe Mastery is inapplicable to the canonical dual-dagger loadout. The source does not supply usable values for remaining Reclaim Energy/Toxic Splash chance clauses, so they remain source-blocked instead of guessed. No comparable confirmed mismatch was established. |
| Scout/Rogue | The pair and Poison Powder routes are covered by helper/runtime tests. `docs/ROM_SCOUT_REMAINING_PASSIVES_AUDIT.md` keeps Exploiting Shot's unspecified stack cap and Deadly Counterattack's missing critical amount/buff duration separate from existing hybrid estimates. These are unresolved source values, not confirmed values that this pass could implement. |
| Mage/Warlock | The ten exact pair skills and source-selected cast/proc branches are covered by pair tests. The Flame Follower identity conflict concerns Mage/Warden, outside Durnik's pairing; it is not mapped by ID alone. No comparable source-confirmed player/owned-NPC mismatch was found for this selected pair. |
| Knight/Scout | Current CoA Blood Punishment was the concrete confirmed mismatch fixed here. Its stale local child timer is not layered onto the current aura rider. The separate base Blood Arrow toggle/cost contract above remains open. |
The old Knight/Scout Lua callback is source-confirmed, but current CoA reuses the exact passive identity and publishes replacement benefits. The replacement is attached to the real caster aura, so cancellation and natural expiry remove it with Blood Arrow rather than waiting for a one-second child-timer poll. Unquantified or absent source behaviors remain open rather than receiving guessed values.
## Ownership and verification
- `src/game/romKnightScoutBloodPunishment.ts` owns the exact caster-aura attachment rule.
- `src/game/romPriestKnightOverrides.ts` owns the learned Knight/Scout passive marker and routes Blood Arrow activation through the helper.
- `src/game/partyRuntime.ts` resolves RoM direct-hit schools from source ability effects and applies active actor-owned damage modifiers in the no-roll Runewaker compatibility path, excluding Holy Blessing from its dedicated resolver. Native stat-mode hits use the existing roll-based outgoing-aura path.
- `src/game/romPriestKnightPairValidation.test.ts` covers the exact passive marker, effect values, aura attachment, and player cast. `src/game/romKnightScoutBloodPunishment.integration.test.ts` exercises player Holy and physical damage, healing taken, immediate cancellation, owned-NPC healing and damage, natural expiry, owner isolation, and both native and compatibility stat rulesets. It also checks Earth Chain's explicit Nature school and Wind Arrows' explicit Physical school.
- Focused validation passed: `npx vitest run src/game/romKnightScoutBloodPunishment.integration.test.ts src/game/romPriestKnightPairValidation.test.ts src/game/romScoutRoguePairValidation.test.ts src/game/romMageWarlockPairValidation.test.ts` (154 tests across four files).
No identity, stat input, health, loot, recovery, level-cap, or readiness scope changed.
+107
View File
@@ -0,0 +1,107 @@
# RoM five-class native scaling and automatic training gear
This targeted check covers Knight/Scout, Priest/Knight, Rogue/Warrior, Scout/Rogue, and Mage/Warlock using the named, race-legal identities in `src/game/romFiveIdentities.ts`. It does not promote RoM builds to Ready or introduce loot progression.
Other RoM classes remain available in the existing generated companion pools; this diagnostic verifies the five requested active identities and does not certify the other classes.
## Character and NPC growth
Player and companion native stats use `deriveCharacterStats(..., "rom")`, dispatched to `romNativeStats.ts`. Class-specific source growth starts from the level-one attributes and repeats `value = value * (1 + percentGrowth) + flatGrowth` for each additional level. Native HP/MP and attack/defense then use the source coefficients for the primary class, equipment, and active modifiers. Wisdom is a distinct attribute rather than WoW Spirit.
The shared simulator activates each named identity's secondary class at level 10 and treats its level as the primary level. The secondary contributes one tenth of its base growth; it does not supply a second complete equipment set. Native secondary Mana pools retain sourced MP, while the primary kit keeps its existing Mana/Energy/Focus resource behavior.
Generated RoM companions explicitly select native stats. A configured companion must explicitly pass `statRuleset: "rom"`; omission deliberately retains legacy WoW compatibility. Existing saved RoM players also retain WoW compatibility unless switched. A player's selector does not overwrite every NPC's independently owned mode.
The follow-up fixed two real NPC inconsistencies. `partyStore.ts` now normalizes creation and level synchronization to the shared finite 1–80 range before deriving gear, talents, resources, and secondary unlocks. Native full HP/MP remain equal to their precise caps after creation, leveling, and gear rescaling; wounded pools stay bounded and defeated actors remain at zero. `combatActorAuthority.ts` now refreshes a native companion's health cap when its source changes, preserving the live actor's precise health fraction. Previously a level-up could calculate the new member cap correctly, then actor synchronization could overwrite it with the old cap. Unchanged source/caps retain the authoritative live actor values.
## Gear without loot progression
RoM has no authentic heirloom item system. The simulator's shared equipment fallback supplies **automatic training gear** for the player and party, using compact ordinary RoM source-item references for these five classes. It fills eligible empty slots and recalculates the reference values with level, class, role, and applicable secondary weapon unlocks. Reference selection and interpolation are simulator policies, not the original game's acquisition or item-upgrade rules.
The existing player and NPC reference curve caps at level 79. At level 80, character base growth continues but automatic gear retains its level-79 values. This avoids inventing unsupported endgame gear. The same cap applies to both owners. Native item payloads are counted once; their accompanying WoW projection is ignored in native derivation.
Training references are not a smooth linear curve: source-item tiers/package anchors and weapon-slot unlocks cause step changes. An exact levels-1–80 audit found byte-identical player/NPC payloads; one example is Rogue's 65→66 increase of 912 DMG and 362 MDMG. At 79→80 all five classes' gear DMG/MDMG stay unchanged while base ATK/MATK grow. In this source version both attack-to-damage coefficients are zero, so gearless native DMG/MDMG are zero; the current shared adapter and ability resolver are still separate from complete native combat.
RoM fallback item names, source labels, and Equipment slot labels now say Training rather than Heirloom. Stable item IDs, internal quality, stat budgets, saved inventory, and assignment behavior are unchanged. The panel explains the level-79 cap. No loot source, drop table, boss reward, card reward, or loot distribution behavior is changed by this work.
## Enemy health
`src/scene/MobPopulation.tsx` passes both `contentCategoryForClass(player.classId)` and the player's selected ruleset to `dungeonEnemyScaling`. The original curve below follows character origin. The later native-only factor applies only to RoM-origin characters using native `rom` stats; RoM characters in legacy WoW-stat mode continue to use the original curve. Dungeon source, NPC composition, and party size do not select the health policy.
Ordinary enemy level follows player level, clamped to 1–80. Bosses have a one-level edge, also capped at 80. Before authored multipliers, RoM trash HP is:
```text
round((1000 + 100 * L + 8 * L²) * (1 - max(0, L - 70) * 0.006))
```
Campaign bosses use the larger of authored baseline HP and a separate durability floor:
```text
max(trashBaseline(L) * authoredHealthMultiplier,
(1000 + 1200 * L + 22 * L²) * 1.15 * finaleOrSliceFactor)
```
Normal campaign finales use a 1.9 floor factor unless explicitly marked standard. Boss difficulty and any per-boss balance override then multiply the result. Bite-Sized bosses instead use their existing interpolated floor/ceiling bands. Boss Testing has its own reduced floor and may use source creature health. Manastorm follows its separate enemy modifiers. Dungeon difficulty chooses encounter/population variants; it is not an extra generic HP multiplier in this helper.
| Player level | RoM trash baseline HP | Boss level | Standard campaign boss floor HP |
|---|---:|---:|---:|
| 1 | 1,108 | 2 | 4,011.2 |
| 10 | 2,800 | 11 | 19,391.3 |
| 30 | 11,200 | 31 | 68,243.3 |
| 60 | 35,800 | 61 | 179,471.3 |
| 79 | 55,651 | 80 | 273,470 |
| 80 | 56,588 | 80 | 273,470 |
These are the legacy WoW-stat baseline/floor examples, not every creature's final HP. The historical curve predates native character stats; the current native-only adjustment is separately anchored and measured below. Neither calculation claims a RuneWaker source mob-HP formula.
Anglo in full Barren Caves has an authored health multiplier of 7.5 and is the default finale, so its 1.9 finale floor dominates from level 10 onward. Its actual registered legacy-mode HP at player levels 1/10/30/60/79/80 is **9,240 / 36,843 / 129,662 / 340,995 / 519,593 / 519,593**; native-stat RoM multiplies those results by the separate boss anchor below. The older `romDungeonHealth.test.ts` boss sample manually used baseline × 7.5 rather than the actual finale floor, and initialized a compatibility-mode player with seed-selected native NPCs. That older sample is not evidence for a complete native five-identity party or the current real boss pool.
The earlier fixed-cohort diagnostic is historical: it rotates five identities into the player seat, explicitly creates four native companions, and samples one real Barren Caves trash spawn and Anglo at six levels (60 samples) while omitting active player damage except Priest healing. It predates exact-pair active player rotations and native-only HP pacing, so its timings and defeats are not current outcomes.
| Player level | Trash kill-time range | Anglo kill-time range |
|---|---:|---:|
| 1 | 15–18 s | 148.2–232.3 s |
| 10 | 4.5–7 s | 82–105 s |
| 30 | 10.5–12 s | 78–118.3 s |
| 60 | 7.6–11 s | 49.5–72 s |
| 79–80 | 2.5–5.4 s | 25–37.5 s |
The saved earlier report records that all 60 samples completed; trash had no companion defeats, while level-one Anglo caused companion defeats in four of five variants. This was a conservative diagnostic because active player damage was omitted, not a balance certification or automatic tuning target. Its 240-second level-one boss limit and 120-second limit elsewhere differ from the current fixed-rotation report.
## Evidence
- `src/game/romFiveNativeDungeonHealth.test.ts`: three targeted checks passed, including the actual RoM/WoW dungeon HP helper, all 60 fixed-cohort samples, and boss difficulty/finale behavior. Diagnostic report: `artifacts/rom-five-native-dungeon-health/report.json` (ignored local artifact).
- Exact gear audit: player/NPC owner contexts match for all five identities; reference payloads were inspected across levels 1–80, including weapon unlocks, source tier jumps, and the 79→80 plateau.
- The final focused selection passed 176 tests across 12 files. The new parity suite contributes 13 cases covering the five native player/generated/configured identities at levels 1/9/10/30/60/79/80, explicit-versus-omitted rulesets, secondary unlock, level bounds, owner gear parity, and full/wounded/defeated pools. Existing native aura/channel/periodic integration and legacy compatibility regression tests also passed.
- Ready-five passed seven Vitest and twenty Python checks. Avatar validation passed 47 tests across ten files before the subsequent party-only fixes; avatar and numerical gear code were not changed afterward.
- Final full production build passed: 8 GB TypeScript project compilation, Vite (1,266 modules), asset audits, compression, and release-bundle verification (5,562 objects, 123 chunks). Final chunks: `index-Ba_szGct.js`, `combatStore-BGky6YlB.js`, and `PartyFrames-CcpsvWIi.js`.
- Exact-final-dist Edge QA passed through `scripts/playtest-stat-rulesets.cjs` using an isolated temporary account/server. Native player tabs, a native Mage NPC owner panel, Training gear labels/cap note, legacy migration, independent saved mode choices, switching locks, build/checkpoint preservation, both native/compatibility dungeon runs, and desktop/390-pixel layouts passed. Visual review confirmed roster and both dungeon character bodies with held starter staffs and closed overlays/loading intro.
- Browser report: `playtest-artifacts/stat-rulesets/results.json` and its eleven referenced screenshots, including `05-native-npc-stats-attributes-desktop.png`. Diagnostics had zero page errors, HTTP failures, or failed application-resource responses; the only console response error was the optional favicon 404. Synthetic legacy/combat/online fixtures remain guard checks, not a live multiplayer certification.
- Final `npm run release:check` and `git diff --check` passed, including untracked files and concurrent unrelated work. The four owned vault notes passed whitespace/EOF checks. The prior stat-ruleset validation remains in `docs/CHARACTER_STAT_RULESETS_2026-10-03.md`; its 219-test result is historical and is not added again to this task's totals. This follow-up supersedes the browser artifacts stored at the shared stat-rulesets path.
## Player-rotation combat follow-up (2026-10-03)
The final diagnostic in `src/game/romFiveNativeRotation.integration.test.ts` uses the shared `BenchmarkController` rotation and damage path, turns each requested identity into the player in turn, explicitly constructs the other four native identities as companions, and samples one real Barren Caves trash spawn plus Anglo at levels 1/10/30/60/65/66/79/80. This is 80 fixed samples with static actors, not a scene-driven dungeon run; navigation and authored encounter mechanics remain outside its scope.
The post-haste-retention report records 80/80 cleared pulls, zero player or companion deaths, and zero invalid cast failures. Trash took 4.5–9 seconds; Anglo took 39–53.4 seconds. The harness checks for a dead target before making another controller decision. Actors remain fixed in place; no navigation or authored encounter mechanics run.
## Native-only enemy health pacing (2026-10-03)
`dungeonEnemyScaling` accepts a selected character stat ruleset with a backwards-compatible default of `"wow"`. Live `MobPopulation` passes the active player ruleset. The added piecewise-linear factor is active only for RoM-origin characters using native `"rom"` stats; it leaves the legacy RoM curve, WoW/CoA-origin results, enemy damage, level, boss difficulty, authored multipliers, and level-80 cap unchanged.
| Character level | Trash scale | Boss scale |
|---:|---:|---:|
| 1 | 0.9 | 0.45 |
| 10 | 1.4 | 0.85 |
| 30 | 1.4 | 0.95 |
| 60 | 1.5 | 1.25 |
| 65 | 1.8 | 1.5 |
| 66 | 2.1 | 1.9 |
| 79 | 3.6 | 2.8 |
| 80 | 3.6 | 2.8 |
Values between anchors interpolate linearly against the clamped 1–80 character level. This is a simulator health budget measured against the five canonical training builds, not a source RuneWaker mob-health formula. The general generated companion pool and RoM readiness state are unchanged.
`artifacts/rom-five-native-rotation/before-native-combat.json` is the earlier 60-sample, six-level comparator; it predates the current native-only health policy and the final eight-level active-rotation matrix. Do not treat it as a paired health-curve experiment. Native amount routing, supported auto-attack channels, limitations, and current verification state are summarized in [`ROM_NATIVE_COMBAT_PASS_2026-10-03.md`](ROM_NATIVE_COMBAT_PASS_2026-10-03.md).
The final production build passed with asset audits, compression, and bundle verification. Exact-dist browser QA passed against `index-D_h9IRuA.js` and `combatStore-BiA9BOQG.js`; 11 screenshots were captured and four representative roster, dungeon, NPC-stat, and 390×844 mobile screenshots were visually reviewed. No page/server errors occurred and the network response-errors list was empty; the only console error was the optional existing favicon 404. A release check passed on 249 paths; the final documentation update requires the final hygiene/release check. The full source hit/defense model and RoM readiness certification remain outside this follow-up.
+25
View File
@@ -0,0 +1,25 @@
# RoM Group Heal radius — 2026-10-04
The generated RuneWaker row for Group Heal (`490281`) says it restores HP to
"all party members within range of 120." `src/game/romAbilityCatalog.ts`
already translates that local source distance into `ability.radius: 12` through
`areaRadius`'s `/ 10` conversion. Its party-scoped heal effect did not carry that
radius, so `healingRecipientIds` applied its existing 30 m fallback.
The catalog now copies Group Heal's derived ability radius onto only its
party-scoped heal effect. Player casts in `combatStore.ts` and companion casts
in `partyRuntime.ts` both pass this effect through the shared
`healingRecipientIds` resolver. The resolver still requires a living recipient
and line of sight, and its shared fallback remains unchanged for other spells.
`src/game/romGroupHealRadius.integration.test.ts` checks the catalog mapping,
the 12 m inclusive boundary and 12.01 m exclusion, living and LOS filtering,
player and companion execution, and Soul Source's unchanged party-heal
fallback.
Focused validation passed: `npm test -- --run
src/game/romGroupHealRadius.integration.test.ts` (3 tests). The npm `pretest`
hook also ran `loot:generate` and reported 9 bosses, 23 items, and 23 table
entries. No build or full suite was run by this subprocess. The coordinated
final build, regression selection and bounded Stockade evidence are recorded
in [the parent report](ROM_HEALING_PARTY_RANGED_FOLLOWUP_2026-10-04.md).
@@ -0,0 +1,119 @@
# RoM healing, party selection and ranged follow-up (2026-10-04)
The owner approved four follow-ups to the Stockade continuation: Group Heal's
recipient radius, the active native-five party complement, recurring player
Auto Shot, and source verification of Blood Arrow's damage curve through the
level-80 cap. Independent GPT-6 Luna extra-high subprocesses implement and
audit the mechanics; the parent coordinates shared files, build and live QA.
## Current implementation and source boundary
Group Heal source 490281 already supplied an ability radius of 12 metres, but
its party-heal effect omitted that field and the shared resolver used its
30-metre fallback. The catalog now copies the sourced radius onto only that
spell's party-heal effect. Player and companion execution share the living,
distance and line-of-sight recipient rules. Other spells keep their existing
recipient contracts. See [the radius report](ROM_GROUP_HEAL_RADIUS_2026-10-04.md).
Party generation now receives the player's exact ordered RoM class pair from
ordinary entry and avatar preloading. If the other active identities can fill
the requested roles, generation excludes the player's identity. The full
five-person party therefore uses the other four canonical identities around
each supported player. Unsupported pairs and unfillable compositions keep the
prior role-pool fallback. Actor stat rulesets and readiness remain independent.
See [the selection report](ROM_NATIVE_PARTY_SELECTION_2026-10-04.md).
Scout/Rogue player Auto Shot now uses learned primary skill 492589 through
ordinary ability bindings. Its independent timer produces recurring ranged
Physical attacks at 80% ranged weapon DPS. Supported native actors use the
source ranged damage and interval; unsupported/custom gear falls back to the
resolved item's shared DPS and speed. The existing automatic Training Gear
bow is valid with an empty inventory; compatible assigned gear overrides it
and unequipping that gear restores the training bow. Haste is resolved once in
both stat modes. The active mode suppresses melee/off-hand swings, follows
target selection, can always be stopped and clears on target loss, missing resolved gear,
death and reset. Owned Blood Arrow charges its 2% maximum-HP cost once per
committed shot attempt and skips unaffordable attempts. The source does not
quantify its contribution from the last offensive skill; that bonus remains
omitted. Local range and other runtime constraints are documented in
[the Auto Shot report](ROM_PLAYER_RANGED_AUTOSHOT_2026-10-04.md).
The Blood Arrow audit has not established a current skill-rank formula through
80. Current Scout/Rogue and Knight/Scout pages each publish only the maximum
skill-rank-105 value of +104.5%; that single point does not establish rank 80.
The local RuneWaker snapshot supplies one historical +10% component. Retain
the current 10% approximation until additional matching source evidence is
available. See [the source audit](ROM_BLOOD_ARROW_SCALING_2026-10-04.md).
## Validation and evidence
The final seven-file mechanic regression selection passes 96 checks: Auto
Shot 13, native auto attacks 5, Blood Arrow/Blood Punishment integration 15,
Group Heal radius 3, party selection 32, Blood Arrow evidence boundary 1 and
catalog semantics 27. Ready-five passes seven Vitest and twenty Python checks,
for 103 distinct Vitest and twenty Python checks in the required selection.
The shared production build passes TypeScript/Vite, prebuild asset audits,
static compression and release-bundle verification. Its frozen entry is
`index-CLGdfcYj.js` for the initial probe. The initial live run exposed an
explicit-assignment-only guard that rejected the automatically supplied bow.
The authoritative resolved-loadout correction now passes its fresh-profile
and custom-item fallback checks. The replacement production build passes all
hooks with entry `index-Cvmh-YKE.js`; its recursive 123-JavaScript manifest
SHA-256 is `ed3cb65752426810c84be15184306114fdf36d3804a23f917213fc854f4651d4`.
Bounded full Stormwind Stockade run `20261005-042203897` passes its three
required live criteria in 61.051 seconds on that unchanged freeze. Both
normally generated parties are the player's exact four-identity native-stat
complement. Normal Attack order supplies natural injuries; a completed player
Group Heal gives Caelan 92 effective HP. Its full-health self event is entirely
overheal. Two sourced Auto Shot Physical hits deal 37 effective damage each,
2,612 ms apart. Normal stop input clears the mode and produces no Auto Shot
hit during the observed stop window. The captured restart is not attempted
after target death, so restart remains inconclusive live. The focused recurring
test verifies stop-window silence/no cost, reactivation without an immediate
or catch-up hit, and a fresh full-interval deadline followed by one shot.
Blood Arrow is already owned and active at the Scout entry. Its raw HP windows
overlap combat and recovery; exact HP-only cost is integration-test evidence,
not inferred from aggregate live deltas. NPC recipient position is unavailable
in the Group Heal snapshot, so the 12 m boundary remains deterministic test
proof. Actual screenshots show loaded bodies, equipped silhouettes and HUD,
with doorway/party overlap and camera occlusion. There are no page or asset
HTTP errors; the console records a favicon 404. Raw JSON and images are in
`playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/` and details
are in [the live report](ROM_HEALING_RANGED_STOCKADE_PLAYTEST_2026-10-04.md).
Initial run `20261005-040846797` preserves the fixture name-casing failure.
Run `20261005-040932648` preserves the rejected automatic bow and unengaged
Defend/selection-only encounter. Neither is relabeled as successful. This
follow-up proves bounded mechanics, not another full clear or balance pass.
Supplemental same-build run `20261005-042845955` passes the same criteria in
61.658 seconds: Caelan again receives 92 effective Group Heal HP and two
Physical Auto Shot hits deal 36 each. Normal Stop party order preserves the
target briefly, then Auto Shot cancellation clears its state with no shot in
the observed stop window. The target still dies before restart; the original
Defend order is restored. Root also inspects that run's stopped-party and
cancel/restart screenshots. No further live run is required for this scope.
A supplemental generic `combatStore.test.ts` run passes 110 of 111 checks and
reports a Chronomancer resource expectation mismatch (414 expected, 369
observed). The same exact test fails with committed HEAD versions of the
changed production modules, so this mismatch predates the follow-up. The
[baseline replay report](../artifacts/rom-healing-ranged-baseline/README.md)
records its source-only scope and both logs. It is not hidden inside the
passing required selection.
Final validation also passes the standalone TypeScript check after the new
restart assertions, using the project's 8 GB Node heap setting. A preceding
check with Node's smaller default heap exhausted memory. `npm run release:check`
passes for all 20 changed game paths, including untracked files. Exact EOF
newline/trailing-whitespace checks pass for 26 changed game and relevant vault
text files; both Git diffs are reviewed and the real index remains unstaged.
Earlier Stockade full-clear and Vow captures remain evidence for their recorded
builds. They do not verify this new code. New live checks use ordinary entry,
bindings, movement and casts, with read-only runtime telemetry. Any isolated
level-30 profile preparation must be identified in the live report.
The baseline is clean game commit `6114a229`; pre-existing vault changes are
preserved. This task does not add loot or ammunition, raise the level cap,
promote a Needs Testing build, commit or deploy.
@@ -0,0 +1,56 @@
# RoM healing and ranged Stockade diagnostic — 2026-10-05
**Outcome: complete for the focused live criteria.** Two bounded ordinary-UI runs verified an effective Group Heal, two source-attributed recurring Auto Shot hits, and the generated native-five party complement at both normal Stockade entries. This is not a full Stockade clear, readiness promotion, or balance certification. The report filename remains the date originally assigned; the browser runs occurred on October 5.
## Runner and fixtures
The reusable runner is [`scripts/playtest-rom-healing-ranged.cjs`](../scripts/playtest-rom-healing-ranged.cjs). It opens the full Stormwind Stockade (`stormwind-stockade`) through Dungeons → WoW and the ordinary content-download/role flow. It creates two disposable level-30 profiles through the visible character UI. Level and secondary-class preparation occurs only in isolated pre-entry progression.
| Player fixture | Exact companions checked at normal entry | Live focus |
| --- | --- | --- |
| Priest/Knight healer, `Romhealpk` | Knight/Scout tank; Mage/Warlock damage; Rogue/Warrior damage; Scout/Rogue damage | Learned Group Heal, normal action-bar cast, healing events and available recipient distances |
| Scout/Rogue damage, `Romrangesr` | Knight/Scout tank; Mage/Warlock damage; Priest/Knight healer; Rogue/Warrior damage | Learned Auto Shot, ordinary action-bar activation/cancellation, and descriptive Blood Arrow HP/resource windows |
At both entries, all four companions matched the exact native-five complement for the player's ordered identity pair; each had level 30 and the RoM stat ruleset. The runner recorded all action-binding layers and used normal UI assignment where needed. It did not inject or prescribe companions. Movement, facing, targeting, rendered UI orders, and ability casts were ordinary inputs. Store snapshots were read-only; there were no in-combat HP, resource, cooldown, position, cast, target, or party mutations.
## Frozen build and browser health
The approved frozen build used 123 recursively fingerprinted JavaScript assets. Both successful runs started and ended with the same manifest SHA-256, `ed3cb65752426810c84be15184306114fdf36d3804a23f917213fc854f4651d4`. `dist/index.html` was 812 bytes with SHA-256 `786875f7ca8e26df9d896810ecc7820e1b68f9a46b799d5922fd5cf61b638175`. Key served bundles were:
| Asset | Bytes | SHA-256 |
| --- | ---: | --- |
| `index-Cvmh-YKE.js` | 5,476,357 | `f7346f993f9dde4f23c5678513413dd7a5cba9e6fbf6b942b280f472c72b8c8f` |
| `GameRuntime-Bvkmd8ZT.js` | 354,351 | `517f0c6d4d2a753b6aee8852c546aa213205ca276816f8444fb135960a531a1a` |
| `combatStore-Q2hxVe7P.js` | 5,373,025 | `d8ca4427d693f24111a84ff55ce454b0ef0f2e0bcc51615018083231e746e6d6` |
| `PartyFrames-Cy8eifsT.js` | 2,293,069 | `821ceea9ac9cdc7b94e9e4248a8e39f6ff1a6cf48c9a907dea904cf8e196bce0` |
| `romAbilityCatalog-CD84SmiY.js` | 1,797,034 | `b66428b14f2fd5055344129f436d14a9a52e14b04a527ee689ceac8f5302f574` |
The primary run recorded 145 JavaScript response events and all returned HTTP 200; the required fingerprinted bundles were served successfully. Four repeated `basis/basis_transcoder.js` responses are outside the 123-asset fingerprint manifest and had no response hash. Across both successful runs there were no page errors and no HTTP errors. The only console error was a local `favicon.ico` 404.
## Preserved attempts
The first attempt, [`20261005-040846797`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-040846797/), stopped before dungeon entry when the character UI normalized fixture names to initial-cap plus lowercase. Its `failure.png` and `failure.json` are preserved; the harness now uses canonical names.
The next attempt, [`20261005-040932648`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-040932648/), reached both normal entries and verified both complements, but remained inconclusive: Defend/selection-only input did not create a natural Group Heal opportunity, and Auto Shot could not start with empty explicit inventory under the then-current equipment guard. The source was corrected to use the existing automatic Training Gear loadout. This run remains preserved and is not counted as success evidence.
## Primary complete run
[`20261005-042203897`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/) completed in 61.051 seconds with all three required evidence flags true and an unchanged frozen manifest. Its roster, normal-entry, Group Heal, encounter-stop, Scout action, and cancellation images were inspected.
- **Group Heal:** The Priest/Knight's learned source 490281 (`rom-priest-primary-8`, radius 12, 3-second cast) was normally bound and cast from the action bar while a rendered Attack party order was active. A player-sourced healing event (ID 104) restored 92 effective HP to a Scout/Rogue companion (1,679 raw; 1,587 overheal). The self-recipient event (ID 105) was entirely overheal. The companion's runtime position was unavailable, so the event does not establish a live 12 m boundary measurement.
- **Auto Shot:** After ordinary movement/targeting/facing and a rendered action-bar start, scheduler state selected a real Defias Inmate at 4.78 m. Two distinct player-to-enemy physical hits tagged `rom-scout-primary-57` / source 492589 landed for 37 effective damage each (event IDs 102 and 117). Auto Shot cancellation cleared its scheduler target and next-shot state. Restart was not attempted because the live target died during the post-cancel window.
- **Blood Arrow:** The owned aura was already active before direct test input. The raw snapshots show HP `2293.53 → 2247.53 → 2247.53 → 2201.53` from a `2293.53` maximum and resource remaining at 100. No player incoming-damage or healing events appeared in the recorded windows. The frozen source contract intentionally emits no separate self-cost event; these snapshots are descriptive and are not used to prove the exact two-percent cost.
Primary screenshots include [`priest-knight-roster.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/priest-knight-roster.png), [`priest-knight-stockade-entrance-party.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/priest-knight-stockade-entrance-party.png), [`priest-knight-group-heal-attempt-1.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/priest-knight-group-heal-attempt-1.png), [`scout-rogue-roster.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/scout-rogue-roster.png), [`scout-rogue-stockade-entrance-party.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/scout-rogue-stockade-entrance-party.png), [`scout-rogue-blood-arrow-state.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/scout-rogue-blood-arrow-state.png), [`scout-rogue-auto-shot-target-1.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/scout-rogue-auto-shot-target-1.png), and [`scout-rogue-auto-shot-cancel-restart.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/scout-rogue-auto-shot-cancel-restart.png). The rendered bodies, equipment and HUD are present, though doorway/party overlap and close-camera occlusion remain visible.
## Supplemental stop-before-cancel run
[`20261005-042845955`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042845955/) also completed the required criteria in 61.658 seconds with the same unchanged asset manifest. It independently observed a 92-effective-HP Group Heal and two positive Auto Shot physical hits (IDs 100 and 115, 36 effective damage each) against a real target at 4.24 m. The runner sent the normal party order `Defend → Stop → Defend`, and the Stop button's pressed state and restored Defend state were captured. Auto Shot cancellation cleared scheduler state, but the target died before a restart attempt; restart remains inconclusive. Blood Arrow snapshots were the same descriptive values and provide no standalone cost proof.
Inspected supplemental images include [`priest-knight-group-heal-attempt-1.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042845955/priest-knight-group-heal-attempt-1.png), [`priest-knight-group-heal-encounter-stopped.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042845955/priest-knight-group-heal-encounter-stopped.png), [`scout-rogue-auto-shot-target-1.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042845955/scout-rogue-auto-shot-target-1.png), [`scout-rogue-auto-shot-cancel-party-stopped.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042845955/scout-rogue-auto-shot-cancel-party-stopped.png), and [`scout-rogue-auto-shot-cancel-restart.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042845955/scout-rogue-auto-shot-cancel-restart.png). These images show the same doorway and camera occlusion noted above.
## Limits
This was a bounded encounter at the Stockade entrance, not a clear or broad party-balance evaluation. The live Group Heal observation proves an effective event on one generated companion but cannot validate the 12 m cutoff because the companion position was null. Deterministic focused integration coverage owns the exact-radius, living-recipient and line-of-sight checks for player and companion casts. Likewise, Auto Shot cancellation was verified, while a successful restart could not be observed before the natural target's death. Blood Arrow's exact two-percent max-HP debit remains source/integration evidence: this live report records the owned aura and HP/resource/event windows without attributing ambiguous HP deltas to the cost.
Raw JSON, all screenshots, build hashes, party-complement assertions, scheduler snapshots, event IDs, and run diagnostics are preserved in each linked run directory.
@@ -0,0 +1,48 @@
# Interrupt, sustain, route and Killing Spree follow-up — 2026-10-04
## Scope
The authorized follow-up checks Vow of Silence against Lady Anacondra, repeated native RoM level-60/80 healing sustain, real Barren Caves/Wailing Caverns route play, and the separate Killing Spree catalog assertion. Work uses Luna subprocesses with extra-high reasoning. The five active native identities remain Needs Testing; the WoW Ready five remain the routine certification scope.
Recovery formulas, automatic Training gear, the level-80 cap, saved-profile compatibility defaults and loot scope are preserved. No readiness promotion, commit or deployment is included.
## Interrupt source correction
The previous Lady Anacondra Vow attempt resolved while the same Lightning Bolt cast remained active. The pinned AzerothCore source uses `CreatureImmunitiesId` as a foreign key, but the importer treated it as a literal signed mechanic mask. Row -93 resolves to Fear and Horror only. The importer now loads the exact pinned immunity table, normalizes its enum-indexed mask into the existing runtime representation, and preserves legacy literal-mask sources. Missing nonzero foreign keys fail closed. Generated Lady creature 3671 now has legacy mask 8388624 and no Silence/Interrupt immunity. The table fixture and SHA-256 make regeneration reproducible; no Vow duration or recovery formula changed.
## Repeated NPC healing sustain
The native Knight player and owned Priest/Rogue/Scout/Mage party complete three consecutive source Anglo pulls at each of levels 60 and 80, with a 10-second rest followed by a 90-second rest. Actor health, Mana, effects and cooldowns continue between pulls. All six pulls clear with no deaths or empty Priest Mana pools.
The owned Priest's level-60 delivered healing is 39,753 effective plus 70,327 overheal (63.9% overheal); level 80 is 183,396 effective plus 80,845 overheal (30.6%). Telemetry separates raw event amounts, delivered healing, actual Mana pools, starting Mana capacity and estimated cast costs. Every observed direct Heal begins on an injured party/player snapshot, even though Regenerate is active. A HoT-only suppression rule was not justified, so healing AI and sourced recovery remain unchanged. This is a six-pull diagnostic rather than every-encounter sustain certification.
## Killing Spree audit
The old representative-signature failure came from requiring a generic non-utility effect for a source periodic-dummy selector. The test now requires Killing Spree's exact `class-script` shape while preserving its dedicated ten-strike player regression. The independently verified child 61851 provides a 20% all-school damage buff for two seconds; the player aura previously used 1% and now uses 20%. All 81 focused Rogue/catalog/rotation tests pass.
Companions still lack the Killing Spree script handler. The player's immediate assaults and deterministic target selection remain approximations. This targeted audit does not promote Combat Rogue or establish full timing/targeting parity.
## Campaign route review
The ordinary roster-to-dungeon entry baseline found the floating Roster details toggle covering Continue at 1440×900. Single-screen roster spacing now reserves a strip below the footer for that toggle; dual-display layouts retain their own spacing. Final normal-click checks at 1440x900 and 390x844 show no overlap; no force click is used in final evidence.
Both original campaign dungeons receive 90-second entrance/encounter segments through normal selection and inputs. Barren Caves records 69.34 units of accumulated travel, 41 keyboard steps, 15 effective player heals (~6,155 healing), seven player damage events (549 damage), and no party deaths. It naturally levels the UI-created Priest/Knight from 30 to 31. The subsequent fixed-level harness assertion stopped that cross-route session; its completed Barren phase remains valid. Wailing Caverns is replayed independently from a fresh level-30 profile and records 23.76 units of travel, 15 keyboard steps, 11 effective player heals (~6,831 healing), three observed entrance enemy deaths, and no party deaths. Wailing records zero player damage, so that segment establishes targeting/healing and companion combat rather than player DPS. Both final phases have no page errors; the logged 404 is identified as favicon.ico.
The first longer Wailing attempt lost its tank after repeated out-of-range heals while the automated healer fell behind. Its trace is preserved. The corrected harness prefers the available ranged spell, reads actual companion positions, follows wounded allies into healing range, waits for casts, and uses normal Attack/Defend inputs to contain the entrance encounter. No game balance or recovery formula was changed to obtain the rerun.
Evidence is in `playtest-artifacts/native-routes/final-20261004-051413627/` (completed Barren phase), `final-20261004-051737171/` (failed Wailing positioning diagnostic), and `final-20261004-052623521/` (corrected Wailing phase). Midpoint and endpoint screenshots were visually inspected. Cave geometry partially occludes endpoint views; these are bounded input/combat checks, not full route, boss-clear, navigation-guide, camera or compact-layout certification.
## Detailed evidence
- `docs/VOW_OF_SILENCE_AUDIT_2026-10-04.md`: source identity, immunity and interrupt investigation.
- `docs/ROM_NATIVE_SUSTAIN_AUDIT_2026-10-04.md`: actor-attributed repeated-pull Mana and healing diagnostics.
- `docs/WOW_KILLING_SPREE_AUDIT_2026-10-04.md`: catalog assertion and dedicated runtime audit.
- `docs/ROM_NATIVE_ROUTE_PLAYTEST_2026-10-04.md`: normal campaign entry, movement, targeting and healing segments, roster hit checks, screenshots and telemetry.
## Validation
Focused checks pass: 40 interrupt/enemy integration cases, five importer cases, 81 Rogue/catalog/rotation cases, and the six-pull sustain diagnostic. The final Vow-only rerun passes eight cases. Ready-five certification remains green with seven Vitest and twenty Python cases. App TypeScript and the production build pass, including asset audits, compression and bundle verification.
The coordinated build contains `index-CAMDJqEC.js`, `combatStore-t7bO4yKt.js`, `GameRuntime-otPnJCWI.js`, `PartyFrames-BsBsesPR.js`, and `index-499eecpe.css`. The CSS includes the roster footer clearance fix. Existing chunk-size/import warnings remain; the asset performance audit reports no new regressions.
Vault diff checks and owned-text hygiene pass for 26 files. The repository release check initially found an extra EOF blank line in the concurrently edited `src/game/benchmark/coaFirstParty.ts`; only that final newline was normalized, preserving its code. Final release hygiene is checked after these documentation edits.
@@ -0,0 +1,27 @@
# RoM Knight/Rogue Panther's Blessing dodge proc
## Source contract
The current CoA [Knight/Rogue skill list](https://chroniclesofarcadia.com/wiki/skills/list/6-3?locale=ru) identifies 493047 as Panther's Blessing, a level-45 passive. Its current tooltip says a dodge restores 10% HP and 1% MP. This identity is separate from level-50 God's Vengeance 499934.
The current skill row publishes no rank curve, and the tooltip does not define the percentage bases or integer rounding. The simulator therefore applies the flat published 10% and 1% values to the actor's own maximum HP and mana pools, rounds each request to a whole point, and caps each restore at the current maximum. These are explicit simulator interpretations, not separately published CoA details.
The local RuneWaker 493183 child describes a different shield-conditioned chance to grant +2 Dodge. Its chance and required shield check are unavailable, so the child stays suppressed while the current CoA proc runs independently.
## Runtime ownership and boundaries
`src/game/romKnightPanthersBlessingRuntime.ts` owns the exact Knight-primary/Rogue-secondary, learned-passive, living-owner, resolved-dodge gate and the pool-basis calculation. `src/game/combatStore.ts` owns both real-player and generated-companion incoming-hit resolution, so it applies the helper there and records the HP and mana outcomes under `rom-knight-rom-rogue-elite-45`.
The trigger is the combat resolver's actual `combatResult.dodged` outcome. Misses, parries, blocks, ordinary hits, other class pairs, and an unlearned level-45 passive do not trigger it. The generic `damagePlayer` adapter has no dodge result and does not synthesize one. The current resolver exposes dodge for melee attack kinds; this runtime does not add another chance roll, cooldown, shield requirement, rank scaling, or event source.
The player scalar pools and player actor snapshot are updated together when present. Companion health and mana are written through the authoritative actor and mirrored to the party member.
## Validation
Focused validation:
```text
npm test -- --run src/game/romKnightPantherDodgeProc.integration.test.ts src/game/romKnightPanthersBlessingRuntime.test.ts src/game/romKnightOverrides.test.ts
```
The focused command passed all 21 tests across the integration, helper, and catalog files. The integration cases cover a capped player restore, a generated-companion restore and mirror, below-level gating for both actor paths, and the no-synthetic-dodge boundaries for direct damage and a spell hit. The catalog test confirms the stale 493183 child remains absent.
@@ -0,0 +1,38 @@
# RoM Knight periodic and triggered reference audit
This audit closes the bounded review of triggered references on Knight-primary RuneWaker rows. It distinguishes source data that exists locally from fields the player exporter omits, and records where current combat behavior still depends on missing state or target semantics.
> **Current runtime correction:** Panther's Blessing 493047 follows the current same-name Knight/Rogue passive and restores 10% max HP plus 1% max MP after a resolved dodge. The max-pool basis and whole-point rounding are simulator interpretations; the legacy RuneWaker +2 Dodge child remains suppressed. God's Vengeance is the separate level-50 passive 499934, linked to learned child Punishment 499909. See the [Panther runtime note](ROM_KNIGHT_PANTHER_DODGE_PROC_2026-10-02.md) and this audit's current table entries; older source rows below document the legacy conflict.
## Source and runtime ownership
The player catalog retains component IDs and trigger spell IDs, but not `MagicRunPlot.PlotName`. The field exists in `F:\Projects\Runewaker\SourceCodeVS2019\Libraries\Union\RoleData\ObjectStruct.h` (`MagicRunPlot::PlotName`); `MagicProcess.cpp`'s `Magic07_RunPlot` reads that field and calls the Lua function for proc targets. The local `F:\Projects\Runewaker\Resource\data\magicobject.db`, `magiccollectobject.db`, and the referenced `Resource\luascript\*.lua` files are present. `scripts/runewaker-pipeline/export-player-catalog.mjs` currently does not export the RunPlot name, so the omission is in the generated player record, not evidence that the local scripts are missing. This audit does not expand the exporter into a Lua-runtime implementation.
Generated player source IDs and component payloads are in `src/game/romPlayerCatalog.generated.json`. Translation and the unsupported generic radius fallback are in `src/game/romAbilityCatalog.ts`; Knight-specific passive shaping is in `src/game/romKnightOverrides.ts`; pair-specific Knight and Scout behavior is in `src/game/romPriestKnightOverrides.ts`. Incoming-hit, periodic, and companion event wiring lives in shared combat/runtime files and needs a separately scoped change.
## Knight-primary trigger references
| Parent → child | Local source/script result | Current implementation and disposition |
| --- | --- | --- |
| 490192 → 490469 | Component 500149 triggers on magic-attack rebound during its 30-second shield. Child payload 500213 is Light damage. | Covered by the custom Shield of Discipline path in `romAbilityCatalog.ts`; complete for this audit. |
| 492935 → 493094 | Component 503192 triggers every 3 seconds for 15 seconds. Child RunPlot is `lua_star_ParryState` in `01129.lua:120`: it checks `EM_RoleValue_ParryState == 1`, checks buff 503192, then adds buff 503200 (Lua argument 20); if 503192 is absent it cancels 503200. Component 503200 carries +5000 Parry and a 15-second lifetime in the local object data. | Current runtime applies +5000 Parry for 15 seconds and consumes it after two blocks; the hidden periodic aura is also kept for 15 seconds. The `EM_RoleValue_ParryState` set/reset condition and the distinct conditional 503200 application are not represented. Prerequisite: map that role-state value and its event lifecycle before wiring the child; do not turn the Lua argument into a duration by assumption. |
| 492939 → 493246 | Component 503207 triggers on timeout after 15 seconds. Child RunPlot calls `lua_Dy_DELAnother(503207, 506236)` in `01129.lua:518`; the helper cancels 506236 only when 503207 is absent. Both local effects are 15 seconds. | No distinct numeric combat payload is added by the child. Natural expiry aligns; early removal of 503207 and the resulting cleanup of 506236 are not represented. Prerequisite: source-backed buff-removal/timeout event semantics if early cancellation is intended to be observable. |
| 493273 → 491614 | Component 502056 triggers on hit. `lua_star_ProtectAlly` in `01129.lua:313` reads last damage, the buff owner, and `BuffInfoType_Power` (`PLV`), removes 502056, then computes `p = 0.40 + 0.008 × PLV`; it casts child 491612 on the original buff owner with `floor(abs(lastDamage × p / (1 − p))) × 2`. | `romPriestKnightOverrides.ts` currently uses a fixed 40% one-hit redirect and +20 Parry. This is an active approximation: it does not preserve the buff's `PLV` or apply the rank-dependent split formula. Prerequisite for a correct shared player/companion implementation: define the source value stored as `BuffInfoType_Power` for 502056, then carry it through the application and incoming-hit paths in `combatStore.ts`/`partyRuntime.ts`; cover it in `romPriestKnightPairValidation.test.ts`. |
| 499923 → 499910 | Component 623167 triggers every second for 30 seconds. `lua_bico_kni_sco_es_70_blood` in `02708.lua:257` cancels 623167 whenever owner buff 500871 is absent. | Superseded by current CoA's matching Knight/Scout passive: +15% received healing and +5% Light/Holy damage while Blood Arrow is active. `romKnightScoutBloodPunishment.ts` attaches both modifiers to the actual owner Blood Arrow aura, so removal/expiry ends the rider without a separate child timer. The base Blood Arrow still uses the local 30-second, periodic-HP-cost model; CoA toggle/per-ranged-skill cost parity remains open. See `docs/ROM_FIVE_MECHANIC_GAPS_2026-10-04.md`. |
| 495402 → 497924, 497926 | These are timeout children of the old Leopard Instinct active effects. The local `un_495402_cancelbuff` RunPlot in `02383.lua:182` cancels old buffs 620144/620141/620142/620143. | Superseded by current CoA's passive stack behavior. Existing pair handling suppresses the old active effects; do not restore these timeout children. |
| 493047 → 493183 | The local RuneWaker 493183 child is a MagicFunc1 on-hit self-reference. Its tooltip conditions a chance-based +2 Dodge aura on being attacked while Shield of Valor or Shield of Discipline is active, but the numeric chance and required-shield check are absent. | Current CoA's [Knight/Rogue row](https://chroniclesofarcadia.com/wiki/skills/list/6-3?locale=ru) identifies 493047 as Panther's Blessing, a level-45 passive that restores 10% HP and 1% MP on dodge. The exact learned Knight/Rogue passive now triggers from the actual resolved incoming dodge result for the player and generated companions. Because CoA does not publish the percentage bases or a rounding rule, the simulator uses the owner's maximum HP and mana pools and rounds to whole points; each restore is capped to its current pool. The published current row has no rank curve, so these percentages are flat and no scaling is inferred. The legacy 493183 shield-conditioned +2 Dodge child stays suppressed. God's Vengeance is the separate passive 499934. See `docs/ROM_KNIGHT_PANTHER_DODGE_PROC_2026-10-02.md`. |
| 499934 → 499909 | Current CoA's [Knight/Rogue list](https://chroniclesofarcadia.com/wiki/skills/list/6-3?locale=ru) identifies God's Vengeance as passive 499934, level 50: when Punishment hits a target with exactly four Holy Seal stacks, reset Shadow Step. The local LearnMagic row independently makes child 499909 learnable by Knight/Rogue at level 50 with key item 542123 and prerequisite 499934. Its MagicCollect components match general Punishment 490151's payload; 499909 remains a separate child row rather than an alias of general 490151. | The exporter emits this exact linked child as a second level-50 row. It keeps Punishment's direct damage and ordinary Seal consumption, scales the one hit by the pre-spend Seal count, and removes the retired Seal DoT. Player and generated-companion casts reset only the casting actor's learned Shadow Step (490344) when the exact child lands against its own target with four of that target's Seals. A landed combat event is the runtime's “hits” boundary, including full absorbs; miss/dodge, wrong pair, missing passive/Shadow Step, general 490151, and three/five-stack cases do not reset. Companion AI selects 499909 when it is ready and usable, otherwise retaining its general Punishment fallback. |
| 491606 → 497471 | Parent component 502049 triggers every 2 seconds for 6 seconds. Child RunPlot `Dy_KM15_01` exists in `01129.lua:571`; it reads `MagicPowerLv_SP + 42` and casts 491607 on the owner. MagicCollectObject 491607 is present and names components 502050 and 502051. Component 502050 has Light damage fields `damagePower=-20`, `fixedValue=-0.2`; 502051 is the tooltip's damage-reduction aura. | The periodic damage and reduction component are retained by the catalog override, but the child's actual affected-unit geometry/radius is not established. See the separate radius finding below. |
| 490078 → 490079 | Parent component 502103 triggers every 3 seconds for 18 seconds. Child RunPlot `YOYO_JOB6_4_ExpeditionBlessing` exists in `02842.lua:236`; it advances owner buffs 500140 → 500146 → 500168 → 500169. | This is the old RuneWaker child behavior, not the current War Prayer result. Current CoA/patch behavior applies a personal Holy Seal stack every 3 seconds; the existing six-pulse runtime follows that current behavior. Do not import the stale four-buff sequence as Holy Seal. |
## Holy Light Domain's 10-unit fallback
`areaRadius()` in `romAbilityCatalog.ts` matches the tooltip phrase “surrounding targets within range.” Holy Light Domain is self-targeted with catalog range 0.1, so the generic fallback assigns radius 10. The focused `romKnightPeriodicRuntime.test.ts` currently asserts that radius and verifies the compatibility behavior: targets at x=5 and x=9 receive the effect, while x=12 does not. This is test coverage for the existing approximation, not source evidence for a 10-unit radius.
The child source record exposes `effectRange=50` and `rangeType=3`, but the player export does not preserve a verified conversion of those fields to the runtime's target geometry. The RunPlot confirms the child cast is made on the owner; it does not define the server's affected-unit selection rule. Until a verified interpretation of the child target/range fields is available, leave the radius explicitly unsupported: do not treat 50 as a runtime radius, do not infer a 5-unit radius, and do not map child 497471 to another effect.
## Validation
- Focused validation passes: `romCombatMechanics.test.ts`, `romKnightPeriodicRuntime.test.ts`, `romKnightOverrides.test.ts`, `romPlayerCatalog.test.ts`, `partyAbilityAi.test.ts`, and `romKnightGodsVengeance.integration.test.ts` (77 tests total). The touched Knight Holy Seal semantics case also passes when run alone from `romAbilityCatalogSemantics.test.ts`.
- The previously reported baseline failures are resolved by matching behavior to current sources: Divine Punishment emits one direct hit plus the seal-scaled vulnerability rather than two damage outputs; current CoA God's Vengeance resets Shadow Step on the linked 499909 Punishment at four Seals, rather than expecting the retired Holy Seal DoT.
- Official source rows reviewed: the current CoA Knight/Rogue list gives 493047 Panther's Blessing (passive, level 45) and 499934 God's Vengeance (passive, level 50); the official [10.6.1 patch notes](https://chroniclesofarcadia.com/en/patch/10-6-1-1000) document Holy Seal's damage/vulnerability behavior and removal of its periodic damage. Shadow Step is local Rogue general 490344, level 28 ([official Rogue/Mage list](https://chroniclesofarcadia.com/wiki/skills/list/3-2)). Panther's Blessing event ownership and the explicit max-pool simulator interpretation are covered in `docs/ROM_KNIGHT_PANTHER_DODGE_PROC_2026-10-02.md`.
@@ -0,0 +1,25 @@
# RoM Mage/Warden Flame Follower 494051: raw source/runtime audit
Status: unresolved; no runtime mechanic was added.
## Finding
The available local RuneWaker data does not provide a numeric Fireball critical-rate bonus or a trigger phase for the old Mage/Warden passive. Keep `494051` unresolved. Current CoA Flame Follower `490244` is a later active-summon revision, and the current reuse of `494051` for Purgatory Fire does not establish the old passive's behavior; see [the identity/source review](ROM_MAGE_WARDEN_FLAME_FOLLOWER_SOURCE_REVIEW.md).
## Raw RuneWaker record trace
The local `Resource/data/magiccollectobject.db` and `magicobject.db` hashes match the RuneWaker source hashes recorded in `src/game/romPlayerCatalog.generated.json`. The player-catalog exporter records component IDs and selected fields, but omits `MagicCollect.LUAScript`, `MagicCollect.CheckUseScript`, `MagicBase.CheckUseLua`, and `MagicRunPlot.PlotName`; the latter is the 64-byte `MagicRunPlot` field at raw MagicObject record offset `0x284..0x2c3`.
- Raw MagicCollect `494051` is at file offset `4,180,772` in the 140-byte-header, 1,032-byte-record database. It has source effect type `2` and target type `0`. Searching every aligned word across that record finds no other MagicCollect or MagicObject ID, and the record contains no printable script-name string. The source skill tooltip remains qualitative: it says Fireball cooldown is reduced by one second and Fireball critical rate is increased.
- Raw Fireball MagicCollect `490204` references MagicObject components `620199`, `500379`, and `623146`, and passive MagicCollect records `490221` (Eruption), `491589` (Outburst), and `499588` (Meditation Path). It does not reference `494051`.
- Fireball damage components `620199` and `500379` have `MagicFunc=0`, `Attack.CriticalRate=0`, and `MagicRunPlot.PlotName="none"`. The status component `623146` has `MagicFunc=1`, `Attack.CriticalRate=0`, and `PlotName="none"`; its raw `CheckUseLua` field names `un_623522_CD`.
- `Resource/luascript/02709.lua` defines `un_623522_CD` as an owner-marker gate: it returns false when the owner already has buff `623522`; otherwise it adds that buff and returns true. It does not read `494051`, modify critical rate, or alter Fireball cooldown. In the server, `CheckUseLuaProc` invokes this kind of component check for per-target `HIT` results only, before applying the component. That documents the phase of this separate Fireball child check, not the Flame Follower passive.
- No RuneWaker Lua file contains `494051` or `Flame Follower`. The engine's `Magic07_RunPlot` path is component-scoped: it calls a named plot for each target with `HIT` or `CRITICAL` outcomes. The `494051` row has no linked MagicObject, and Fireball's three referenced MagicObjects do not use `MagicFunc=7` or name a plot, so this engine rule does not identify a Flame Follower trigger.
The relevant definitions are in `F:\Projects\Runewaker\SourceCodeVS2019\Libraries\Union\RoleData\ObjectStruct.h` (`MagicRunPlot`, `CheckUseLua`, and `LUAScript`), and the dispatch is in `F:\Projects\Runewaker\SourceCodeVS2019\Server\NetGameServer\MainProc\MagicProc\MagicProcess.cpp` (`Magic07_RunPlot` and `CheckUseLuaProc`). The generated extractor's selected-field behavior is visible in `scripts/runewaker-pipeline/export-player-catalog.mjs`.
## Missing evidence
The raw old passive row has no identified critical-rate amount, child effect, script name, or link to a Fireball component. The linked Fireball graph has no critical-rate payload for this passive and no handler that checks whether `494051` is learned. The general engine callbacks establish what an attached check or plot would do, but the available source does not attach either callback to Flame Follower.
Closing the item requires a matching-version source that connects the learned `494051` passive to a Fireball event and specifies the critical-rate amount. Without that source, the amount, whether the passive responds to a cast, a landed hit, or a critical hit, and any associated conditions remain unknown. No helper or integration test should encode those values until the missing source is recovered.
@@ -0,0 +1,37 @@
# Flame Follower (local RuneWaker 494051) source review
Status: unresolved; no runtime mechanic was added from this review.
## What the local catalog contains
The generated RuneWaker row is the Mage-primary / Warden-secondary elite passive at level 25, source skill ID `494051`, named **Flame Follower**. Its tooltip says it reduces Fireball's cooldown by 1 second and increases Fireball critical rate. Its source component list is empty, so the generated data supplies no critical-rate value, proc or application details, rank curve, or targeting rules. The local general Fireball row is ID `490204`.
## Current Chronicles of Arcadia identity
The current [CoA Mage/Warden skills page](https://chroniclesofarcadia.com/en/wiki/skills/list/4-7) assigns **Flame Follower** ID `490244`, Mage/Warden level 25. It is an active spell: 10% MP, range 1, instant, 60-second cooldown, and summons a Flame Incarnation for 30 seconds. The summon cannot attack or be attacked. While active, Fireball gains Earth damage, increased critical-hit chance, and reduced cooldown; using Fireball also reduces Flame Follower's cooldown.
The same current page uses ID `494051` for **Purgatory Fire**, a Mage-primary level-26 active spell, not Flame Follower. It also lists the Mage/Warden-modified Fireball as ID `490248`; the local RuneWaker catalog uses `490248` for the general Fire Ward row and `490204` for Fireball. These identity conflicts mean current CoA IDs cannot be copied onto the old RuneWaker rows by numeric ID alone.
## Revision history relevant to the conflict
- [CoA patch 11.1.1.5000](https://chroniclesofarcadia.com/patch/11-1-1-5000) says Flame Follower was changed so Fireball additionally inflicts Earth damage. It provides no critical-chance amount.
- [CoA patch 12.1.0.4000](https://chroniclesofarcadia.com/patch/12-1-0-4000) reworked Flame Follower into the 30-second Flame Incarnation summon and describes Fireball reducing its active cooldown by 4 seconds. That patch gives the initial 3-second cast, 60-second cooldown, and 10% MP cost.
- [CoA patch 12.1.0.5000](https://chroniclesofarcadia.com/patch/12-1-0-5000) made it usable while moving, shortened cast time from 3 to 2 seconds, and raised Fireball's cooldown reduction from 4 to 5 seconds.
- [CoA patch 12.1.0.6000](https://chroniclesofarcadia.com/patch/12-1-0-6000) changed the spell to trigger global cooldown instead of having a cast time. The current skill page now reports it as instant.
This is a later active-summon revision, not evidence for the missing number or trigger semantics of the older local passive. In particular, the current page's phrase “increased critical hit chance” still has no numeric amount.
## Source-backed fields and unresolved fields
| Question | Evidence | Result |
|---|---|---|
| Current name, ID, and pair | Current CoA skill list | Flame Follower is `490244`, Mage/Warden active level 25. Local `494051` is a different, old passive row. |
| Old passive's critical amount | Local RuneWaker tooltip only says “increasing ... critical rate”; current CoA page says “increased critical hit chance” without a value | Unknown. Do not substitute critical damage/effectiveness or a guessed critical chance. |
| Eligible Fireball triggers | Old local tooltip names Fireball; current reworked page and patch history say casting/using Fireball reduces the summon skill's cooldown | Old passive's trigger phase (cast, landed hit, or another event) is unknown. The current Fireball row is ID `490248`, while local general Fireball is `490204`; do not bridge by name alone. |
| Rank behavior | Local row is a single passive elite level-25 row with no components. Current CoA active entry is level 25; its separate Fireball is rankable to 105 | No old passive rank curve or amount is source-backed. Current active skill rank data does not establish old passive ranks. |
| Duration/cooldown | Current CoA active skill and patch history | The **new active summon** lasts 30 seconds with a 60-second cooldown; the old passive's duration and cooldown are not applicable/known. |
| Target conditions | Current active description: summoned pet cannot attack or be attacked; skill summons it on self | No old passive target condition beyond naming Fireball. No crit condition (for example, target type, hit requirement, or crit roll timing) is specified. |
## Implementation decision
Keep the local old passive unresolved and do not add a helper or runtime effect. A correct CoA-era replacement would require a deliberate migration of the Mage/Warden class-pair catalog to the active `490244` identity, plus reconciling the current CoA Fireball `490248` against local Fireball `490204` and deciding how to represent an untargetable summon. This review does not silently make those cross-version identity changes. If the older passive must be reproduced instead, an authoritative historical CoA tooltip or implementation detail giving its critical chance and trigger timing is still needed.
+78
View File
@@ -0,0 +1,78 @@
# RoM native combat pass — 2026-10-03
The later [native resolution and enemy damage-type pass](ROM_NATIVE_COMBAT_RESOLUTION_PASS_2026-10-03.md) supersedes the open defense/hit/critical, negative DotMagic and special/multi-target input boundaries below. This report preserves the original amount/rotation pass and its historical validation.
## Scope and status
This pass connects source-derived native amount bindings to the existing combat runtime for the five targeted identities: Knight/Scout tank, Priest/Knight healer, Rogue/Warrior damage, Scout/Rogue damage, and Mage/Warlock damage. `romFiveIdentities.ts` remains the identity owner. The new shared-rotation profiles are exact-pair and role gated; they are clean-room heuristics informed by local active catalog data and the add-on source research in [`ROM_ROTATION_ADDON_REFERENCE_2026-10-03.md`](ROM_ROTATION_ADDON_REFERENCE_2026-10-03.md). No add-on code was retrieved or installed. CurseForge's archive request reached a Cloudflare JavaScript/cookie challenge, so the profile priorities are not copied presets.
The native amount routes improve source fidelity, but this is not a full RoM combat port or balance certification. Formula outputs still pass through HealerMan's shared target and combat-state machinery. Unsupported source shapes and gear intentionally retain the documented simulator fallback. The five identities remain targeted-test builds; no readiness or random-pool promotion is included.
## Binding and amount routing
`romAbilityCatalog.ts` attaches `romNativeSource` skill/component identities to supported active RuneWaker ability effects. `romNativeCombatAmount.ts` resolves those identities against the generated source binding catalog. The native route runs from `equipmentAdjustedCombatAmount` only for a RoM stat ruleset and a nonnumeric, source-bound ability amount. It tries the specific direct HolyHeal branch, the supported direct damage branch, and the periodic HolyHeal snapshot. If a source binding or required profile is unsupported, it returns no native amount and the existing shared HealerMan coefficient/scaling path continues.
`romNativeMagicLevel(level)` uses the active character level clamped to the project's 1–80 range as the simulator's effective `MagicProc.MagicLv`; it does not infer skill rank or a separate skill-level curve. The active player-build companion amount routes use the source `player` classification for the native player ExRate branch even though the runtime owner is an NPC actor. This is an explicit simulator choice for the five playable builds, not a claim about every ordinary RoM NPC.
Direct native damage requires a supported source attack component and the active five-class training-weapon profile. Since the stat sidecar has no item provenance or weapon speed, the adapter compares the complete native gear payload with the canonical automatic training profile before reversing its weapon contribution. Unverified/custom gear, unsupported class pairs, missing weapons or component bindings, unsupported calculation types, and unavailable school rates return an unsupported result; the generic shared amount path then remains in force. These gates prevent inferred weapon values from being presented as source-derived.
The direct damage helper returns a positive mean source power after its source target-count factor, before source random range/critical handling and target defenses. Its checked `MagicAttackCalENUM` fixed-type branches support 0, 1, 2, 3, and 5–9; throw, prior-hit, and shield-category inputs remain unsupported because the stat sidecar lacks those exact source values. The consumer also declines components marked `isShareDamage`, or nonzero `decreaseArg` on nonzero `rangeType`, until it receives the runtime target count and ordinal; the pure amount helper can represent those fields but the current consumer does not claim area-damage exactness. Reflected Shot has a regression check for this fail-closed behavior. Supported single-target ability amounts pass to the shared target-resolution path for modeled hit/critical rules, resistance/armor, target auras, absorbs, and damage application. It does not yet resolve every RoM source hit/avoidance point, native defense channel, ability random roll, or source critical-rate field.
`nativeTrainingAutoAttackProfile` provides native physical weapon damage and intervals for player Knight main-hand attacks and NPC Knight/Rogue melee plus Scout Bow attacks; NPC Rogue offhand is also covered. Player Rogue offhand handling requires an explicitly present equipped inventory item. It does not claim a player Scout bow auto profile: player Scout Shot instead uses the native direct-damage route for its actual bound Shoot hit. Caster ambient basic-spell attacks retain their generic interval and MDMG policy. Player melee timing explicitly reads the existing common haste aura via `resolveAuraStatValue` because native stat re-derivation does not populate the shared haste fields; race-affix timing is retained as well. Four focused auto/source-action cases passed: player Knight Main_DMG/source interval with semantic 50% haste, NPC Scout Bow/source clock with ranged haste, NPC Rogue offhand Sec_DMG/offhand clock with melee haste, and a player Scout Shot resolving an actual bound hit. These are source-backed channels, not complete native hit/avoidance, armor, variance, or critical models.
Outgoing damage-over-time still uses native stat inputs through the shared simulator amount path. The source DotMagic snapshot implemented in this pass covers healing; source-native periodic damage remains future work.
## Direct HolyHeal
`romNativeHealing.ts` resolves only source-bound calculation type 5 components. It applies the source MagicLv-adjusted `OrgPower`, clamped `SpellTime`, Wisdom/MND contribution and cap, MDMG coefficient, MPow, HealPowerRate, and HealPoint. The amount adapter samples `RandomRange` at its midpoint (`randomUnit = 0.5`), producing mean source power; the common healing resolver still handles its critical and overheal behavior.
The caster amount is computed without recipient-specific HealAbsorb modifiers. At each real recipient, `nativeHolyHealTargetAmount` applies that target's HealAbsorbRate and HealAbsorb once, unless the component says to ignore absorption. Normal aura/talent and healing-result stages then run through the shared resolver. This prevents the recipient's native absorption stats from being folded into caster power and applied a second time. Group heals resolve each recipient independently.
## Periodic HolyHeal snapshot
Source DotMagic healing is separate from direct HolyHeal. `nativePeriodicHealSnapshot` resolves the supported positive-HP DotMagic component when the buff is applied, using the caster/recipient native stats and the source rank, duration, tick interval, and effective MagicLv. The source rank correction computes a `Buff.Power` snapshot with MND, MDMG, HealPowerRate, HealPoint, the available MPow input, and the target absorption inputs, then stores the integer tick amount. Later ticks reuse the stored value; they do not rerun the caster formula or apply target absorption again.
This follows the observed Runewaker `CalAddDotMagicLv`/`BuffProc` ordering for bound components. The current sidecar exposes neutral all-magic MPow but not every element-specific `BodyRate`, so callers must not read the current default as proof that all elemental healing rates are 1. Unsupported DotMagic shapes return no native snapshot and continue through the existing fallback.
## Rotation and validation boundary
`romFiveRotation.ts` selects only the exact ordered `(statRuleset, primary, secondary, role)` tuple at level 10 or above. It retains learned catalog damage actions as low-priority fillers, while pair-specific guards cover cooldown/setup priority, useful target lifetime, AoE target minimums, emergency healing, current DoT ownership, and near-expiry refresh. The shared evaluator and its party/benchmark callers continue to enforce learned ability, cooldown, resource, range, target, and movement readiness. Pre-secondary levels and unsupported pairs stay on the existing semantic path. WoW keeps its existing specialization selector and is not filtered by the native RoM guards.
`romFiveRotation.integration.test.ts` covers all five exact pairs against active learned catalog abilities, a healthy Priest/Knight using Group Heal for injured allies, Urgent Heal before throughput when an ally is critical, actor/target-owned DoT refresh timing, and the unchanged WoW profile selector. The focused module and integration suites pass together (17 tests).
The fixed full-player diagnostic in `romFiveNativeRotation.integration.test.ts` rotates each of the five identities into the player seat, creates the other four native party members explicitly, and uses the shared BenchmarkController against a real Barren Caves trash spawn and Anglo at levels 1/10/30/60/65/66/79/80. This is 80 fixed samples, not a scene-driven encounter: actor positions are static and encounter mechanics/navigation are not simulated. The test writes `artifacts/rom-five-native-rotation/report.json`. `artifacts/rom-five-native-rotation/before-native-combat.json` preserves the earlier 60-sample, six-level pre-native-combat baseline. The final post-haste-retention report records 80/80 pulls completed, no player or companion deaths, and zero invalid casts. Trash kills were 4.5–9 seconds and Anglo was 39–53.4 seconds. The harness now checks for a dead target before requesting another player decision, so post-kill no-target attempts are not counted.
## Native-only health pacing
`dungeonEnemyScaling` now accepts the selected character stat ruleset, defaulting to `"wow"` for existing callers. Live `MobPopulation` passes the active character's ruleset. A piecewise-linear enemy-health factor applies only when the character source is RoM and the selected ruleset is native `"rom"`; legacy WoW-stat RoM characters retain their prior curve, and WoW/CoA-origin characters are unchanged. The factor changes neither damage nor enemy level, boss difficulty, authored multipliers, or the level-80 cap.
The anchors are indexed by clamped character level and each row is [trash health scale, boss health scale]:
| Level | Trash | Boss |
|---:|---:|---:|
| 1 | 0.9 | 0.45 |
| 10 | 1.4 | 0.85 |
| 30 | 1.4 | 0.95 |
| 60 | 1.5 | 1.25 |
| 65 | 1.8 | 1.5 |
| 66 | 2.1 | 1.9 |
| 79 | 3.6 | 2.8 |
| 80 | 3.6 | 2.8 |
This is a targeted native RoM simulator pacing policy measured against the five requested builds, not a claim about RuneWaker monster-health formulas or full balance. It does not alter loot, progression, source enemy damage, or readiness. The ordinary randomized companion pool is now restricted to the active five identities; the broader configured factory remains available for explicit party construction. This diagnostic's five fixed identities do not promote readiness or broaden the general pool.
## Current verification status
The focused 15-file selection passed 210 tests. Direct and periodic native healing coverage passed 14 player/NPC cases. The source-damage follow-up passed 13 focused tests: seven helper cases, two player/companion amount-parity and Reflected Shot fail-closed cases, and the four actual auto-attack cases above. Ready-five passed seven Vitest and twenty Python checks, avatar validation passed 47 tests, and the final TypeScript project check passed. One separate `combatRotation.test.ts` case still fails its existing unsupported-only `Killing Spree` expectation; that unrelated behavior is unchanged here. The final production build passed with asset audits, compression, and bundle verification. Browser QA passed on the current `index-D_h9IRuA.js` and `combatStore-BiA9BOQG.js` chunks; 11 screenshots were captured and four representative roster, dungeon, NPC-stat, and mobile screenshots were visually reviewed. There were no page/server errors and the network response-errors list was empty; the only console error was the optional existing favicon 404. `npm run release:check` passed on the final 249 changed paths, including untracked files; `git diff --check` passed. The worklog is closed; the unrelated Killing Spree test and remaining source-formula boundaries are documented above.
The fixed diagnostic instantiates only the five requested identities. The ordinary randomized companion pool is now restricted to those five, while the configured factory remains broader for explicit compositions. The pass does not alter the loot path, raise the level cap, change enemy damage, or promote RoM readiness.
## Source and validation references
- Source formulas and archived boundaries: [`ROM_NATIVE_STATS_SOURCE_2026-10-03.md`](ROM_NATIVE_STATS_SOURCE_2026-10-03.md), [`CHARACTER_STAT_RULESETS_2026-10-03.md`](CHARACTER_STAT_RULESETS_2026-10-03.md)
- Exact-pair add-on research and clean-room policy: [`ROM_ROTATION_ADDON_REFERENCE_2026-10-03.md`](ROM_ROTATION_ADDON_REFERENCE_2026-10-03.md)
- Native amount code: `src/game/romNativeCombatAmount.ts`, `src/game/romNativeHealing.ts`, `src/game/romNativeDamage.ts`
- Native rotation code and focused coverage: `src/game/romFiveRotation.ts`, `src/game/romFiveRotation.test.ts`, `src/game/romFiveRotation.integration.test.ts`
- Targeted fixed-cohort diagnostics: `src/game/romFiveNativeDungeonHealth.test.ts`, `src/game/romFiveNativeRotation.integration.test.ts`
No loot/progression, legacy/global enemy-HP curve, gear-cap, or readiness-promotion change is part of this pass. A separate native-stat RoM health budget was added and leaves the compatibility curve unchanged.
@@ -0,0 +1,43 @@
# Native RoM combat resolution and enemy damage types — 2026-10-03
This follow-up implements the requested native defense, hit/avoidance/critical, outgoing periodic-damage, special-input and multi-target consumers, and checks enemy damage classifications for both WoW and RoM. It supersedes the open native-combat boundaries in `ROM_NATIVE_COMBAT_PASS_2026-10-03.md`; the earlier report remains historical evidence.
The later [enemy equipment, encounter and pressure pass](ROM_NATIVE_ENEMY_ENCOUNTER_PASS_2026-10-03.md) supersedes this report's equipment/manual-enemy-formula limitations and final damage-budget/browser evidence. The measurements below describe this earlier resolution pass; the native health anchors remain current.
## Actor and source boundaries
Every player and party member retains their own stat ruleset. Supported canonical active-five native builds resolve against an exact imported RuneWaker NPC using `romNativeCombatResolution.ts`. The incoming path derives the recipient's own secondary class, gender and ruleset before choosing native resolution. WoW-mode recipients keep their compatibility resolver even when another party member uses native stats. Native points are never converted into WoW ratings.
`export-rom-native-combat-data.mjs` owns the compact source growth, FIX, skill, spell-binding and population-entity mapping data. `runewakerNpcId` is carried from population registration to combat state independently of WoW creature/server entry IDs. Player level remains capped at 80. The source provider accepts an explicit NPC level 81 in its tests; this does not raise the live scaling cap, and the final diagnostic's enemy levels stay at or below 80.
Canonical training gear and the five exact active class pairs are the supported player source scope. Missing source NPCs, custom/unverified gear, ambiguous source equipment or unsupported source calculations retain a declared shared fallback. NPC source derivation does not replace the game's authored/scaled encounter health pools or damage budgets. No loot, matchmaking or readiness promotion is included.
## Damage calculation, hit gate and school
These source fields have independent meanings. MagicCollect `EffectType` selects the hit gate. MagicObject `Attack.CalType` selects the direct physical or magical calculation and critical path. MagicBase `MagicType` identifies the native elemental resistance channel. A physical calculation can therefore deal Light damage; classifying every physical calculation as Physical school loses source information. DotMagic retains its own MagicBase `EffectType` semantics.
The compact enemy classifier keeps the WoW and RuneWaker spell-ID namespaces separate. WoW packets retain DBC `DmgClass` and the complete `SchoolMask`; the seven single schools map directly, while composite masks retain the existing authored single-school mitigation policy. Missing source spells and non-damaging script placeholders preserve authored packet types. RuneWaker stores the raw six channels separately from their simulator aliases: Earth/Wind → Nature, Water → Frost, Fire → Fire, Light → Holy and Darkness → Shadow. Exact native resistance lookup continues to distinguish Earth from Wind.
Source-qualified packets feed the existing structured combat events, immunity checks, absorbs and health application. Enemy ranged attacks no longer depend on a delivery-shape guess to select their hit kind. Classification coverage and source gaps are recorded in `ENEMY_DAMAGE_TYPES_AUDIT_2026-10-03.md`.
## Periodic damage and special inputs
`romNativePeriodicDamage.ts` owns source-negative HP/HP_Per DotMagic rank correction and application snapshots. Player casts and companion casts bind the exact skill/component. NPC casts also retain their assigned source MagicLv. Source target defense/resistance and caster power are evaluated at application; ticks reuse stored Buff.Power without new critical, hit, armor or resistance rolls. HP_Per reads the recipient's current maximum HP on every tick.
Enemy periodic effects have their own scheduler and are removed by dispels and encounter resets. Natural expiry preserves the final due tick; the source caster can die while an already-applied periodic effect remains. Native tick amounts then pass through ordinary generic dealt/taken modifiers and shields once. Unsupported snapshots retain the existing path. The exact source/runtime cases and unsupported reapplication/resource shapes are documented in `ROM_NATIVE_PERIODIC_DAMAGE_SOURCE_2026-10-03.md`.
The direct and periodic components of one source MagicCollect share the per-target application hit gate. Native hit/dodge/miss seeds therefore use a common cast-target key; critical/block/parry rolls retain their individual packet keys. Incoming periodic application also retains the actual attack revision. An exact native gate remains valid even when an unsupported direct calculation needs the shared amount/mitigation adapter: a passed gate disables the adapter's additional miss/dodge roll. The imported Big Ripper CalcType 4 regression covers this boundary. Cross-system WoW `incoming-*-hit` aura adjustments are not mapped into the native source gate; that mixed-aura bridge remains outside the active-five source scope.
The active-five source audit found Throw fixed inputs and raw ShieldDef inputs, with no prior-hit fixed types. Canonical training Throw derives the source Fin.Throw_DMG channel, including the second DMG_Per factor; shield calculations use raw BaseEQ shield defense, excluding fixed WearEq DEF. Prior-hit inputs remain explicit unsupported values until a real source consumer needs them. Multi-target source power receives actual recipient count and ordinal in both player and companion loops. Source sharing and ordinal falloff are applied once; the generic AoE falloff does not multiply the native result again.
## Validation
The source-resolution diagnostic before the health adjustment cleared all 80 fixed pulls with no deaths or invalid casts, with both selected NPCs source-supported. Trash took 4.5–17.7 seconds and Anglo 24–85.5 seconds. Those measurements justified changing only the native RoM health factors; the compatibility curve, damage budgets, difficulty multipliers and cap remain intact. `before-native-resolution-pacing.json` preserves this distinct baseline.
The final native health anchors are [trash, boss]: level 1 [0.4, 0.3], 10 [1.0, 0.6], 30 [1.1, 0.85], 60 [1.5, 1.5], 65 [1.8, 1.9], 66 [2.6, 2.8], and both 79/80 [4.5, 4.8]. Intermediate levels interpolate linearly. These are measured simulator training-party budgets, not RuneWaker monster-health formulas. The static cohort is diagnostic evidence for these five requested builds, not an all-class balance certification.
The final report clears all 80 pulls at levels 1/10/30/60/65/66/79/80, with zero invalid casts, player deaths or companion deaths. Both the actual trash NPC and Anglo are native-supported in every sample. Trash is 4.9–8.7 seconds and Anglo 40.5–58.5 seconds. The harness asserts source support, successful kills and absence of invalid casts/deaths; positions remain fixed, so this does not certify encounter movement or every dungeon.
Focused validation passed 140 tests across 18 files, followed by six shared-gate/periodic checks after the final result-field cleanup. Native HP/pacing checks passed 7/7. Ready-five checks passed 7 Vitest and 20 Python cases; avatar/equipment checks passed 47 cases during this follow-up. The final production build stages passed: bootstrap and asset audits, TypeScript, Vite, compression and release-bundle verification.
The final production browser checks use `index-DyCSc4Cz.js` and `combatStore-nQykOmDD.js`. Stat-ruleset QA covers native defaults, legacy WoW-mode saves, independent player/companion modes, switching guards, equipment panels and a 390×844 viewport. The targeted Boss Testing check covers Anglo's Gulp control effect and Lady Anacondra's Nature-school Lightning Bolt against a native RoM party, with no page errors. It does not cover every boss mechanic or dungeon. Evidence is in `playtest-artifacts/stat-rulesets/results.json` and `playtest-artifacts/native-combat/results.json`; screenshots verify roster/dungeon bodies, staff/shield/weapon silhouettes, native stats and encounter feedback.
@@ -0,0 +1,41 @@
# RoM native combat resolution and source boundary — 2026-10-03
This note documents the narrow native combat resolver in `src/game/romNativeCombatResolution.ts`. It supplies Runewaker hit, avoidance, critical, typed resistance, and ATK/DEF or MATK/MDEF stages to the shared `CombatResult` shape. The resolver accepts only `ruleset: "rom"`; WoW and CoA requests return an explicit unsupported result and never reinterpret WoW ratings as Runewaker points.
## Source inputs and identity
`scripts/runewaker-pipeline/export-rom-native-combat-data.mjs` reads local `npcobject.db`, `magiccollectobject.db`, `magicobject.db`, vocation/race/sex growth, FixTable, and SkillValueBase/JobSkillValue records. It exports a compact `entityIdToNpcId` map from generated population entity IDs to raw Runewaker NPC IDs. `romNativeNpcIdForEntity` only resolves that map. The raw ID is not an AzerothCore `serverEntry` and must not be passed to server-entry registration.
Player hit profiles are bound to exact imported `(sourceSkillId, componentId)` pairs. NPC hit profiles are bound to the NPC's exact source spell row and component. The profile keeps `MagicCollect.EffectType`, `HitRateFunc`, and its two raw arguments separate from `MagicObject.Attack.CalType`, `AttackType`, and `MagicType`: the collect effect selects the source hit gate, calculation type selects physical/magical damage and critical handling, and MagicType selects one of the six elemental resistance channels (Earth, Water, Fire, Wind, Light, Darkness). An elemental school is therefore not inferred from the physical/magical calculation channel.
NPC derived attributes use authored NPC attributes plus the source vocation, race, and sex growth tables at the explicit runtime level. NPC runtime levels accept the source's 1–200 range; the level-80 player cap is not applied to scaled NPCs. Combat snapshots additionally require an available skill-table row (currently through level 100). No source hit/avoidance table is silently extrapolated past its exported rows.
`romNativeNpcEquipment.generated.json` preserves all five main/off-hand candidate IDs (empty entries and duplicates at 20% each), fixed BowEQ/OrnamentEQ IDs, item WearEQ values, refinement and explicitly separate drop metadata. `romNativeNpcEquipment.ts` resolves deterministic source candidate selection, durability/power-quality wear power and verified refine sequences. Supported channels feed native attributes, attack/defense, healing, resistance and main-hand speed/range/damage. Live callers use the NPC-id seed; actor-specific seeds and explicit candidate overrides are available. DropItemAbility metadata is not worn affix data and is not applied. The default selection supports 398/440 imported NPCs, including Barren 101459–101461 and Anglo. Remaining off-hand weapon damage, bow/ornament channels, unknown effects and vocation mismatches fail closed. See [the equipment pass](ROM_NATIVE_NPC_EQUIPMENT_PASS_2026-10-03.md). NPC periodic target/caster data may be present for inspection on an unsupported profile, but callers must gate native combat use on `combatStatus === "supported"` / `nativeCombatant`.
Exact enemy manual fixed/MaxHP packets now use `romNativeEnemyDamage.ts`; their source stages differ from ordinary physical/magical attack formulas and skip those generic power stages. Source absorption/AoE inputs require verified neutral canonical training gear and aura state. Exact source amounts retain authored encounter multipliers and bypass the native shared-damage calibration. Unbound Throw and unknown fixed inputs remain explicit gaps. [The encounter follow-up](ROM_NATIVE_ENEMY_ENCOUNTER_PASS_2026-10-03.md) records the updated runtime boundaries and pressure evidence.
## Combat stages
The positive damage amount arrives with fixed-value and supported ability-power inputs already resolved by the native amount helper. Unless `sourcePowerStagesAlreadyApplied` is explicitly set, the resolver applies the source level-difference multiplier, the attacker's exact typed native magic-power rate, and the defender's exact typed resistance to magical channels. The source resistance routine works on signed negative damage: it adds raw integer resistance when the damage magnitude is large enough, halves damage when resistance exceeds half of the damage, then multiplies by the typed resistance rate. Missing school inputs return unsupported rather than using a guessed school or WoW Nature mapping.
For NPC attackers, source `Global::DLvRate` uses the verified level-difference table, whose result bottoms at 1 and caps at 2. Player attackers use 1. Native mitigation then uses `max(0.2, 1 + ((ATK or MATK)+100 - ((DEF or MDEF)+200)) / max((ATK or MATK)+100, (DEF or MDEF)+200))`. Auto attacks also retain the source 0.3 minimum. The critical or parry multiplier is applied before this defense ratio, and the final amount is truncated once, at the end of those multipliers.
Auto-attack physical avoidance follows the source dodge-then-miss order. Physical miss compares native weapon and Define skill points; a player weapon skill receives the source `+10`, while an NPC uses `level * 2.3` directly. Define skill receives `+10`. Physical hit/dodge uses the source FIX hit base/range and raw point ratio, source body hit/dodge channels, and the non-player-versus-player level adjustment. Spell hit checks use the exact imported MagicCollect function: base, linear level, signed-square level, per-target ordinal, or Shoot. For a physical-effect spell with a non-base function, source physical skill miss is rolled first; integer physical hit rate then modifies the collect hit check, whose failure is reported as dodge. Spells do not use a separate auto-attack dodge roll. Unavailable Shoot skill or invalid source arguments fail closed.
The source physical avoidance table checks block, then parry, then critical. Block and parry rates come from native point-vs-resist point formulas with FIX base and level terms; they are not percentages. Parry also consumes the source ParryRate body-rate adjustment, halves the landed damage, and prevents a critical. A block prevents damage. Imported HP attack types gate block/parry, and callers can disable individual outcomes through `CombatResultRules` for source components or mechanics that disallow them.
Critical profiles use the actual physical or magical `CalType`, not the collect effect or elemental school. Critical points are compared against the target's native `ResistCriticalHit` points and source FIX base/level terms. Direct magic critical uses the source integer threshold and ±10 level adjustment; auto physical critical uses the source floating threshold and ±20 adjustment. The resulting `CombatResult` retains the shared outcome/table fields while source metadata records the selected channel, applied source rates, and defense ratio.
At DoT tick time, `targetMitigationSnapshotted` (also accepted from `CombatResultRules`) bypasses hit, critical, resistance, and DEF/MDEF because application-time native DoT snapshots already contain those stages. Immunity is checked before that bypass. This keeps snapshot damage from being mitigated twice.
## Snapshot factories and explicit simulator policies
`romNativeNpcCombatant(npcId, runtimeLevel?)` is the NPC snapshot factory; `romNativeNpcIdForEntity(entityId)` supplies its raw source ID for imported populations. NPC snapshots are cached by source ID and exact runtime level.
`romNativeTrainingCombatant(stats, trainingGearProfileMatches, weaponSlot)` creates a player/party snapshot only after the caller confirms the complete canonical training gear profile. It reads the compact generated training profile and verified neutral training-item body defaults. Weapon/Define skills use the source SkillValueBase/JobSkillValue maximum at the current player level; this is an explicit simulator auto-training policy, not a claim about an individual character's training history. Custom or unverified gear returns unsupported. Typed magic rates and resistances retain six source channels.
`nativeMagicInputsForType(snapshot, magicType)` exposes the exact typed power rate and resistance for periodic snapshot callers. `romNativePlayerHitProfile` and `romNativeNpcHitProfile` expose only the exact exported binding pairs. `resolveRomNativeCombatResult` returns a full shared `CombatResult` or an explicit unsupported reason; a caller must preserve its damage school and ruleset rather than relabeling a fallback result as native.
## Verification
`src/game/romNativeCombatResolution.test.ts` covers native ATK/DEF and MATK/MDEF ratios, hit ordering, the NPC weapon-skill exception, block/parry, bound hit/calculation channel separation, typed MPow and resistance, NPC level 81, the supported Anglo neutral off-hand, fail-closed non-neutral equipment, neutral verified training supplements, immunity, and snapshotted mitigation. Source-level claims were checked against the local read-only `Runewaker/SourceCodeVS2019/Libraries/Union/RoleData/RoleAttr.cpp`, `RD_ValueCal.cxx`, `RD_ValueCal.inl`, `RD_Normal.cxx`, `RD_Setting.cxx`, `ObjectStruct.h`, and the referenced binary DB layouts. This is a source-derived subset; unresolved equipment, beyond-table skills, unsupported calculation types, missing supplements, and cross-ruleset inputs remain explicit unsupported cases rather than certified native combat.
+63
View File
@@ -0,0 +1,63 @@
# RuneWaker Native Disarm Main-Hand Audit (2026-10-05)
## Finding and scope
The local RuneWaker RoleAttr source initializes a missing main hand as `EM_Weapon_Unarmed` with speed 30, and its unarmed Main_DMG path supplies `Level * 2` when the main-hand base damage is zero. This is enough to replace the training weapon inputs for native Main_DMG-dependent formulas. It does not justify a WoW punch constant or a blanket multiplier. The implementation is opt-in through the native amount adapters; the separate WoW compatibility formula is not changed here.
The verified profile applies to the five active native player-build identities and their generated party-NPC derived-stat snapshots: Knight/Scout, Priest/Knight, Rogue/Warrior, Scout/Rogue, and Mage/Warlock. It retains the existing training-profile `residualFlatDamage` bridge and tracked generic physical-damage multiplier. The native stat model does not represent all weapon-category damage/speed rates, so the profile records a neutral-rate boundary rather than claiming exactness for those channels.
## Primary local source evidence
Paths below are relative to `F:\Projects\Runewaker`. Hashes are SHA-256 of the audited local files.
| Source | SHA-256 | Relevant evidence |
| --- | --- | --- |
| `SourceCodeVS2019/Libraries/Union/RoleData/RoleAttr.cpp` | `8143A90CE826BF3152551A4508D212F186012CBC054E505E426551CB62369C1F` | `Init_BaseEQValue` lines 178–203 initializes unarmed main hand, speed 30, and main DMG/speed factors 1. `_Main_ATKSpeed` lines 533–580 applies generic `AtkSpeed`, main-hand speed factor, all-weapon speed rate, unarmed speed rate, and the weapon's base speed, clamped to 5. `_MainDMG` lines 713–758 applies main-hand DMG factor, all-weapon DMG rate, `DMG_Per`, and unarmed DMG rate; if `BaseEQ.Main_DMG == 0`, it assigns `Level * 2`, then returns `max(1, (Fin.DMG + BaseEQ.Main_DMG) * DmgRate)`. `AddAbility` line 1323 routes type 25 into `BaseEQ.Main_DMG`; lines 1327–1374 route typed main damage and speed rates by weapon category. `MainAtkDamage` line 963 applies source weapon variance after `Fin.Main_DMG`. |
| `SourceCodeVS2019/Libraries/Union/RoleData/ObjectStruct.h` | `708F2D087F2654B97D149AB7124D9CDFFC915CF8BF18108FEFF3F1A45F124C20` | Defines `EM_Weapon_Unarmed` (line 1047) and the typed body-rate fields consumed by RoleAttr. |
| `SourceCodeVS2019/Libraries/Union/RoleData/RoleBaseDef.h` | `BAE1014F3628B4AD05C2E0F08CDCAE14D5F13A0981DAD4D592F2F0A10BFAAB18` | `_BASE_ATTACK_SPEED_` is 40; that default is not the unarmed main-hand value, which RoleAttr sets explicitly to 30. |
| `SourceCodeVS2019/Server/NetGameServer/MainProc/Global_SimpleSchedular.cpp` | `5DCDBDD69EEFE1086E2087AB167270D580884929A083E4E69032C773F7F941AC` | Main-hand auto scheduling adds `int(Fin.Main_ATKSpeed)` to the server clock (line 445), so this source speed unit is milliseconds. The source auto-hit then calls `MainAtkDamage` (line 633). |
| `SourceCodeVS2019/Server/NetGameServer/MainProc/MagicProc/MagicProcess.cpp` | `B2EEE402FDF9AC488ABE62DC8D2EC9C52B312542EF06D95A6B6FF594711CA7C3` | Physics damage uses `Main_DMG * 10 * SpellTime / Main_ATKSpeed` (line 2327). Physics_Point subtracts `Main_DMG * Dmg_MagArg` once for fixed effects or times SpellTime otherwise (lines 2384–2386). These are native ability branches that must see the unarmed main-hand inputs after Disarm. |
| `SourceCodeVS2019/Libraries/Union/RoleData/RD_Normal.cxx` | `5C0C726F469A7BE63D76114015BF169193A88F545209D4A4DEB5E090443C2692` | `CalAddDotMagicLv` lines 2423 onward applies rank correction; its negative physical DotMagic branch reads `Fin.Main_DMG` and `Fin.Main_ATKSpeed` (line 2507). |
| `SourceCodeVS2019/Libraries/Union/RoleData/RD_ValueCal.cxx` | `D7F00AD9E760EC2263F81F231113F165D0D9F29EB2C329593C66F4C6288A69A9` | Confirms the native `Main_DMG` accessor and unarmed category logic in the value-calculation path (lines 2529, 3642–3646). |
The active ability bindings are `src/game/generated/romNativeHolyHealBindings.generated.json` (SHA-256 `CE2F39D602296686382CDC424F9FEA4EFA8DE384093443311E9C8FB6C97AAA04`) and `src/game/generated/romNativePeriodicDamageBindings.generated.json` (SHA-256 `C01E17C4DF2ADB3B3A196D9EE1F84EA752BE94DBA81FB47E23A889599CB63D33`). Their source metadata pins `magiccollectobject.db` (`4aae19865cb07b30f99945aa7319a0096db244ff5e5b4b5d902fc6889474f501`) and `magicobject.db` (`52af13a2d8cfa9a66d4caa2d3c38832edc232f058995a64ef8135a6b82e43691`) for player attack/periodic rows. The native stat-rule artifact pins `racetable.db`, `sextable.db`, `voctable.db`, and `fixtable.db`; `romNativeStatRules.generated.json` SHA-256 is `6DA531D6D56642013155438B93BB55C120A6421C7C12858CAD8C1B934E1E4E99`.
The training item curve used for the bridge is `src/game/generated/romNativeDamageTrainingProfiles.generated.json` (SHA-256 `A3E064F536F4E1EFAFA076D13755DE5DC62C23B20A496AE572F783126DBE3BCB`). It records `romHeirloomReference.json` SHA-256 `4E5194A28C2764838C5862C1F3DB505F5BE3CE99143A4440BAECF5E38C3099BF` and the source item-database hashes: `armorobject.db` `A2F0017C4772165D562EBB08CA0AC51625CDC4453E3670A1501DF7D741D2BAD3`, `weaponobject.db` `2BC28EEBBE413BD6118F027E3FEC1A3953CEF371476937D0B65622C542971A67`, `addpowerobject.db` `D651861FC5918BAC937D726D754D17A92DA34DB5059F9C70AC9F6B2C15711432`, and `string_enus.db` `4FCE021BA9ED110A213E08D3228B2DE57CEC66DDBBC8DCF5753204874D9AB75`. These are the pins recorded by the generated reference, not a claim that the separate active `Runewaker/Resource/data` directory has those same hashes.
## Implemented formula and adapter contract
For a verified active-five native training profile, the source-shaped unarmed main-hand amount is:
```text
Main_DMG_unarmed = max(1, (residualFlatDamage + Level * 2) * physicalDamageRateFactor)
Main_ATKSpeed_unarmed = 30
Main_attack_interval = 30 * 100 ms = 3000 ms
```
`residualFlatDamage` is the existing native training-weapon bridge remainder after the generated profile's weapon contribution is removed. The `physicalDamageRateFactor` remains applied. Main-hand-only rate channels that this stats bridge cannot supply are held neutral and explicitly surfaced as `unmodeledRateChannels`: `Main_DMG_Per`, `DMG_AllWeapon`, `DMG_Unarmed`, `AtkSpeed`, `Main_ATKSpeed_Per`, `AttackSpeed_AllWeapon`, and `AttackSpeed_Unarmed`.
`nativeDisarmedMainHandAutoAttackProfile(caster)` only returns a profile when the current native derived stats match the canonical active-five training-gear profile. It identifies the main source as `runewaker-roleattr-unarmed-main-hand`, has no training weapon item IDs, and leaves `physicalAttack` intact. This profile is the prepared optional override for:
- `nativeDamageCasterAmount(..., targetContext?, mainHandOverride?)`: when the bound native component is calculation type 0 or 9, or has a nonzero fixed contribution of type 2, the adapter validates the override and feeds the lower native resolver a copied training profile whose main hand is `Level * 2`, speed 30, and `sourceItemIds: []`. The residual, generic rates, off-hand, and ranged entries are retained. Other components do not consume the substituted main-hand fields; a ranged branch therefore keeps its existing ranged inputs.
- `nativePeriodicDamageCasterSnapshot(..., magicResistance?, effectiveMagicPower?, mainHandOverride?)`: only the physical negative HP DotMagic rank-correction branch consumes the override. Other periodic branches keep their current source behavior.
In both APIs an omitted override preserves the pre-existing native calculation. A stale or invalid supplied override fails closed for a branch that consumes Main_DMG/Main_ATKSpeed (`null` for direct damage, `undefined` for a periodic snapshot). Custom/unverified gear returns no disarmed profile; callers must keep their existing explicit fallback behavior. This does not grant spell usability or certify native weapon/category prerequisites for every ability.
## Known limits
- This is the source main-hand input before `MainAtkDamage` variance, hit, target defense, crit, and other downstream combat resolution. It is not a complete auto-hit result.
- The native rules sidecar models generic physical damage rate, not all seven unarmed/main/all-weapon rate channels listed above. Their neutral values are a boundary of this implementation, not a source claim that the rates are always 1.
- The profile is verified against canonical generated training gear's tracked aggregate stats. A custom set whose tracked totals differ fails the gate, but a custom set with identical aggregates cannot be distinguished because the native gear payload has no item provenance. Equipment-specific `BaseEQ.Main_DMG` effects and unidentified weapon/category rate modifiers remain unmodeled.
- Existing ability cast/equipment prerequisites remain unchanged and unverified by this amount adapter. Direct abilities continue through their existing shared status/availability checks.
- The active-five generated party-NPC profile test establishes the stats preparation and formula input shape; it does not certify all classes, every NPC type, every ability, or native combat readiness.
## Verification
Focused source tests passed:
```text
npx vitest run src/game/romNativeDisarm.test.ts src/game/romNativeCombatAmount.integration.test.ts src/game/romNativePeriodicDamage.test.ts src/game/romNativeDamage.test.ts
4 files passed; 25 tests passed.
```
The Disarm tests cover all five active identities as player and configured party-NPC derived stats, preserve the residual and tracked multiplier, reject custom gear and stale override values, confirm native main-hand-consuming basic-attack branches change while the ranged Scout Shot remains unchanged, and verify a physical DotMagic rank correction responds to the unarmed inputs. This was a scoped source/runtime test run, not a full balance/readiness pass.
@@ -0,0 +1,34 @@
# Native RuneWaker enemy direct damage — 2026-10-03
## Scope and runtime contract
`src/game/romNativeEnemyDamage.ts` resolves a direct enemy packet only from an exact imported `(NPC ID, source skill ID, component ID)` binding in `romNativeCombatData.generated.json`. `scripts/runewaker-pipeline/export-rom-native-combat-data.mjs` owns that generated binding data. The helper keeps the three source meanings independent: `MagicCollect.EffectType` selects the hit gate, `MagicObject.Attack.CalType` selects this formula, `MagicObject.EffectType` selects the CalType 8 absorber, and `MagicObject.MagicType` remains the native resistance channel. A formula packet reports `sourceHitEffectType`, `componentEffectType`, and `magicType` separately.
The helper implements negative direct-HP CalType 4 (fixed points) and CalType 8 (recipient MaxHP percentage) rows when all source inputs are present. It returns `unsupported` for positive/healing rows, unsupported component shapes, missing exact bindings, missing MaxHP, missing fixed-attribute values, unverified target absorption, or missing non-target AoE rates. It never guesses an NPC from a skill name. The source catalog has 440 NPC rows and currently contains 22 direct CalType 4 components, 11 direct CalType 8 components, and zero direct CalType 2 NPC-bound components. Day of Rain's CalType 2 skill 491183/component 501278 is catalogued, but this snapshot does not attach it to an imported NPC; the helper rejects that unbound pair.
For CalType 4, source power is `DmgPower * (1 + DmgPower_SkillLVArg * MagicLv / 100)`, plus `FixValue * GetValue(FixType) * (1 + MagicLv * FixDmg_SkillLVArg / 100)`. A nonzero fixed term with a nonzero FixType needs an explicit source attribute value. The known None FixType contributes 1. Negative power goes through target `CalMagicDMG` unless `IgnoreMagicAbsorb` is set. A non-target cast then applies source `AEMagicPowerRate * AEMagicDefRate`. The source share factor is multiplied into the absorbed/AoE-adjusted power before integer damage; unshared recipient ordinal attenuation modifies the base-power term before fixed power and target absorption.
For CalType 8, the target's current native MaxHP multiplies the source percentage before absorption. With absorption enabled, CalWeaponDMG or CalMagicDMG is evaluated against that HP-scaled value first and divided by 100 afterward, matching the source expression's order and truncation. Raw MagicObject `EffectType` 1 selects weapon absorption; 0 selects magic absorption. `IgnoreMagicAbsorb` and `FixDotPower` bypass that absorption. Non-target magical rows apply the AoE magic power/defense rates in the ordinary CalMagicDMG branch; `FixDotPower` takes the source's early raw-MaxHP branch and skips those rates. The share factor is applied after integer damage; unshared recipient ordinal attenuation modifies the source percentage before target MaxHP and absorption.
The supported direct point formulas set `resolverDamageChannel: "none"` and mark applicable source power stages as resolved or not applicable. The shared native resolver therefore retains only the independent collect hit gate and does not reapply level damage rate, typed power/resistance, generic DEF/MDEF, criticals, block, or parry. Ordinary damage auras and shields remain later simulator stages. Target source `AB/Abr/MAbr` is a separate formula input: `romNativeTrainingEnemyAbsorbInputs` supplies the verified canonical training profile's neutral values only when gear matches and the caller explicitly confirms no native absorb-channel aura is active. Custom gear or unverified auras fail closed.
The helper explicitly skips `nativeDamageBudgetScale` for exact source formulas because their source points or target-HP percentage already determine the native magnitude. Imported `mob.damageMultiplier` still applies after the formula. Authored encounter health and the simulator's health curve remain independent of native damage calculation.
CalType 2 Throw remains explicitly unsupported by the runtime helper. Its source path uses `Fin.Throw_DMG`, then `CalPhyDamage` applies NPC damage rate, `Global::DLvRate`, and typed resistance before the source combat table; target `CalWeaponDMG` and share damage happen after critical/block/parry. The current runtime has no completion hook at that exact post-table stage, so the helper returns `native-enemy-throw-post-table-absorption-runtime-unwired` instead of a partial amount. This source catalog has zero direct CalType 2 NPC-bound components; Day of Rain (491183/501278) has no exact imported NPC association and is never inferred.
## Source evidence
- `SourceCodeVS2019/Server/NetGameServer/MainProc/MagicProc/MagicProcess.cpp`, `Magic00_AddHP` around lines 2286–2980: direct `AtkCalType` dispatch, fixed/percentage formulas, recipient iteration, share/ordinal behavior, and final integer damage.
- `MagicProcess.cpp` around lines 2532–2610: CalType 4 `OrgPower`, `AddFixPower`, target CalMagicDMG, AoE rates, and share factor.
- `MagicProcess.cpp` around lines 2751–2840: CalType 8 recipient MaxHP calculation, raw component EffectType selection, FixDot/IgnoreMagicAbsorb bypass, AoE rates, and final integer damage.
- `MagicProcess.cpp` around lines 2477–2515: CalType 2 uses `Fin.Throw_DMG`; `CalPhyDamage` around lines 3366–3398 adds its fixed term, applies NPC damage rate, `Global::DLvRate`, and typed resistance. Its target weapon absorption occurs after block/parry/critical handling around lines 3478–3560.
- `SourceCodeVS2019/Libraries/Union/RoleData/RoleAttr.cpp` around lines 178–209: `Init_BaseEQValue` zeroes `Body` and initializes all `BodyRate` entries to 1. `CalWeaponDMG` and `CalMagicDMG` around lines 941–958 define the flat/rate absorption and minimum one-point damage behavior.
- `SourceCodeVS2019/Server/NetGameServer/MainProc/Global.cpp` around lines 8928–8964 defines the recursive source level-difference rate table, including its NPC lower-bound behavior.
- `src/game/generated/romNativeDamageTrainingProfiles.generated.json` is owned by the native training profile exporter. Its 999 selected training items and affixes have resolved source channels; no selected profile supplies AB/Abr/MAbr/AEMagicDefRate. NPC accepted WearEQ types are separately fail-closed when an unhandled nonzero ability appears, so the supported NPC subset has neutral `AEMagicPowerRate` from source BodyRate initialization plus its resolved equipment projection.
- `src/game/generated/enemyDamageTypeSources.generated.json` is owned by `scripts/dungeon-pipeline/export-enemy-damage-types.mjs`; the compact classifier now exports formula names and absorber policy independently of packet class, raw effect type, and MagicType.
## Verification and limits
`src/game/romNativeEnemyDamage.test.ts` covers exact Barren Axe Throw CalType 4 (NPC 101255, skill 492857/component 503019), Snow's Dance CalType 8 (NPC 101535, skill 492438/component 501098), target absorption, target order, AoE source rates, missing inputs, unbound Day of Rain, and canonical/custom training gear gates. Hall of Survivors NPC 102476/skill 493985/component 503044 is the only current non-target, magical-absorb CalType 4 direct NPC row, but its NPC equipment snapshot is unsupported; its AoE arithmetic is unit-tested with explicit source/target BodyRates, while live runtime correctly stays on the fallback. `src/game/mobDamageTypes.test.ts` verifies exported formula metadata and keeps hit-gate, absorber and resistance fields distinct. `src/game/romNativeEnemyDamage.integration.test.ts` covers the actual Treasure Trove packets against canonical active-five player/companion targets at levels 30 and 80.
CalType 2 target absorption remains pending after the shared combat table and is not integrated for current imported encounters because there are no exact NPC bindings. Non-target magical source packets require a verified source AoE-power multiplier; active source auras that may change that channel must remain fail-closed until represented. CalType 4 fixed types outside None require a caller-provided source attribute. The fixed and MaxHP branches intentionally do not claim support for buffs, healing, periodic damage, MP damage, extra PvP-only behavior, or source shapes beyond their direct HP branch.
@@ -0,0 +1,67 @@
# Native RoM enemy equipment, encounter packets and healing pressure — 2026-10-03
This pass completes the requested follow-up to native combat resolution: source NPC equipment, supported fixed/percentage enemy damage, targeted encounter reactions, and measured healing pressure. The level cap remains 80. Existing saved RoM characters retain WoW stats until switched; each player/companion selects its own resolver. No loot, matchmaking, difficulty-slider change or readiness promotion is included.
This report preserves the earlier pass and its shared-regeneration measurements. The subsequent [recovery, equipment and pacing follow-up](ROM_NATIVE_RECOVERY_EQUIPMENT_PACING_PASS_2026-10-03.md) supersedes the 398/440 equipment count and native HP/Mana recovery limitation below.
## Equipment and source damage
`export-rom-native-npc-equipment.mjs` owns the compact NPC candidate/item/refine snapshot. `romNativeNpcEquipment.ts` resolves actual source candidate slots, wear power and known WearEQ channels rather than averaging candidate stats. Main-hand speed/range/damage and supported attributes, attack, defense, healing and resistance feed `romNativeNpcCombatant`. Current live callers use the stable NPC-id default seed; the provider also accepts an actor seed and explicit candidate overrides. Separate copies therefore currently select the same equipment for the same source NPC. Equipment drops/affixes are not attached to loot.
Under that default selection, 398 of 440 imported NPCs have supported native snapshots. The remaining 42 retain explicit fallback: 26 selected off-hand weapon-DMG cases, ten bow/ornament cases, two unknown item effect cases, and four preexisting vocation-sub-ID mismatches. See [the equipment source report](ROM_NATIVE_NPC_EQUIPMENT_PASS_2026-10-03.md) for exact source paths, item coverage and hashes.
`romNativeEnemyDamage.ts` binds exact NPC/skill/component and source MagicLv for manual fixed damage (CalType 4) and recipient-MaxHP percentage damage (CalType 8). These branches preserve their source absorption, integer, sharing and ordinal order; they do not acquire generic ATK/DEF, elemental resistance or critical multipliers. Native target absorption is accepted only for verified canonical training gear and represented neutral aura channels. Non-target magical packets additionally require a supported NPC body/equipment snapshot and verified neutral source AoE power; an NPC with active unverified auras falls back. Generic dealt/taken modifiers and ordinary shields remain in the existing application path.
Source Throw (CalType 2) is audited separately: no exact imported NPC binding currently uses that calculation. An unbound source spell is not attached to an enemy merely to exercise the branch. Missing fixed attributes, unknown equipment or source effects remain unsupported rather than borrowing WoW inputs. See [the enemy formula source report](ROM_NATIVE_ENEMY_DAMAGE_SOURCE_2026-10-03.md).
The live direct-damage consumer uses the source formula amount with the existing authored `mob.damageMultiplier`. It bypasses the new native training-party damage budget for exact CalType 2/4/8 amounts. This prevents multiplying an already sourced fixed or maximum-HP packet by the high-level shared-damage calibration. Source skill rank stays on the NPC binding; this pass does not claim every fixed-damage encounter is balanced when scaled to every player level. Encounter health continues to use authored/scaled pools.
## Encounter behavior
The headless encounter checks use actual Anglo Trample/Bash/Gulp definitions with only initial cooldown accelerated for isolated mechanic tests. Trample and Bash retain their source 1.8-second warning and five-unit range. Moving the player and Mage outside the radius during the warning excludes them while the remaining nearby companions receive the physical packets. Gulp applies to actual nearby recipients; manual player/NPC dispels and a real native NPC Priest cleanse remove control before natural expiry. A real companion interrupt cancels Trample without damage.
An interrupted/stunned/silenced enemy cast now emits its cast-cancel presentation event when clearing the active cast. Previously the simulation cancelled the cast while its telegraph/presentation could remain active. Self-target Regenerate ticks now enter the structured healing ledger with raw/effective/overheal fields; healing itself is unchanged. Both fixes have direct regression coverage.
The pressure harness uses the actual mob/party tick pipeline with scripted stacked/spread positions. It is not a scene-navigation certification. Its 16 pulls cover levels 10/30/60/80 with an active or idle player Priest and the four other exact native builds. A separate 40-case damage integration selection covers fixed and MaxHP packets against all five builds in both player/NPC seats at levels 30/80. These are explicitly requested diagnostics for Needs Testing builds, outside randomized/all-class certification.
## Measured calibration
`before-pressure-tuning.json` preserves the post-equipment, pre-pressure-adjustment baseline. Before tuning, level-80 Anglo dealt only 335–402 effective enemy damage over roughly 40–57 seconds against a 49,210-HP tank. Large spread-party healing totals were chiefly native Vampire Arrows health costs, not boss damage. The report now separates enemy damage from self/other ability damage so those costs cannot masquerade as encounter pressure.
`dungeonBossScaling.ts` exposes `nativeDamageBudgetScale` separately from authored/difficulty damage multipliers. It applies only to a RoM-origin native-stat party's shared enemy-damage budget. Anchors are level 1:1, 10:1, 30:3, 60:10, 65:12, 66:20, 79:40 and 80:40; intermediate values interpolate. `MobPopulation.tsx` passes it into live registration. `combatStore.ts` scales shared attack damage and its attack-power contribution together and handles repeated registration without compounding. The compatibility curve, native health anchors and difficulty controls stay intact.
| Level-80 pressure sample | Enemy damage | Player effective healing | Lowest party HP | Clear time |
| --- | ---: | ---: | ---: | ---: |
| Active Priest, spread | 13,415 | 54,258 | 82.0% | 49.1 s |
| Active Priest, stacked | 13,415 | 13,415 | 82.0% | 41.1 s |
| Idle Priest, spread | 16,098 | 0 | 13.0% | 57.1 s |
| Idle Priest, stacked | 13,415 | 0 | 48.7% | 52.0 s |
The spread sample still includes substantial Scout health costs, recorded separately in `otherDamage`. All 16 pulls cleared without deaths or invalid controller casts. Active healing remains comfortable; idle stacked health falls materially below the baseline. This is a first measured normal-mode training budget, not a difficult-mode or every-dungeon guarantee. Mana minima remain approximately 95–99% for the active samples under the shared regeneration policy. Native MP regeneration, resource sustain and mana-pressure balance remain open; this pass does not imply mana challenge parity.
The regenerated fixed full-player/four-NPC cohort clears all 80 requested pulls at levels 1/10/30/60/65/66/79/80, with no player/NPC deaths or invalid casts. Trash takes 4.9–8.7 seconds and Anglo 42.0–58.5 seconds. Both exact enemy snapshots are source-supported. Static positions omit navigation; the separate mechanic fixtures cover selected movement and reactions.
## Evidence and validation
- `artifacts/rom-enemy-followup/before-enemy-source-expansion.json`: preserved previous native-resolution cohort.
- `artifacts/rom-enemy-followup/before-pressure-tuning.json`: complete 16-pull pressure baseline.
- `artifacts/rom-enemy-followup/pressure.json`: final pressure ledger and ability-level self/other damage.
- `artifacts/rom-five-native-rotation/report.json`: final 80-pull cohort.
- `src/game/romNativeEncounterPressure.integration.test.ts`: six encounter/pressure checks.
- `src/game/romNativeEnemyDamage.integration.test.ts`: player/NPC formula and fallback coverage.
Focused native/source validation passes 141 distinct tests across 22 files, including the 40 exact packet cases and six encounter/pressure checks. The repeat-registration/mode-switch regression also verifies that pressure does not compound or survive a switch to compatibility scaling. The separate 80-pull cohort passes its diagnostic test. Avatar checks pass 47/47; Ready-five checks pass seven Vitest and twenty Python cases. The app TypeScript check passes with the repository's required larger Node heap.
The final `npm run build` passes bootstrap generation, texture/performance audits, TypeScript, Vite, static compression and release-bundle verification. The tested production chunks are `index-pDR2PGJY.js`, `combatStore-7m63VWbc.js` and `GameRuntime-CGZMQPoV.js`. The asset audit has no new regressions; existing chunk-size/static-dynamic-import warnings remain.
Exact production Edge QA passes with no page errors. The UI-created level-30 native Knight/Scout and four native companions enter real Boss Testing scenes for Anglo and Lady Anacondra. Both normal snapshots record native damage budget 3; Anglo attack damage is 289 with authored multiplier 1.3, and Lady's is 354. These are live population-registration checks, not injected mob-stat assertions. Roster and in-dungeon screenshots visibly retain player/party bodies and starter shield/sword/staff silhouettes.
The final `--fixtures-only` run reuses those successful normal-scene snapshots from the same production chunks (`normalScenesReran: false`) and stages actual Anglo Trample, Bash and Gulp individually. Only cooldown/readiness, attack-list selection, threat and positioning are fixture setup; Trample companion actions are paused to keep its warning observable. Each actual source attack keeps its 1.8-second cast, range, effects and telegraph and releases once. Moving out of Trample's hit area produces zero player damage events; Bash retains its five-unit range. Gulp controls a nearby Rogue and clears at/after source expiry; this browser sample has no Priest cleanse evidence. The separate headless test proves NPC cleansing with the Priest outside Gulp's radius. Test setup was corrected to reset position/source attack lists between fixtures; no runtime change was needed.
Evidence is in `playtest-artifacts/native-combat/results.json`, the two normal sample JSON files, roster/normal scene images and six `anglo-*-fixture.png` images. Representative roster, party/dungeon, Trample warning/movement, Bash and Gulp screenshots were visually inspected. This selected production QA does not certify a normal full clear, full navigation, mobile UI or every encounter. Harness syntax checks and repository/vault text hygiene pass; no readiness reviews or dungeon reports were submitted.
The additional `dungeonBossScaling.test.ts` run passes 13 checks and fails four compatibility-pacing expectations: WoW Stockades at levels 1/3 (14.6/15.1 seconds versus a 24.5-second floor), legacy RoM Mage at level 8 (23.6 versus 25 seconds), and legacy RoM at level 80 (11.3 versus 25 seconds). A Luna subprocess copied the committed pre-native scaler from `b16821e` into ignored scratch files and reproduced the two WoW starter failures and the RoM Mage level-eight failure with the current surrounding runtime. It did not replay the exact level-80 healer case; an additional level-80 Mage diagnostic is a different cohort. Committed/current legacy scaling outputs match for all four original inputs, and these omitted-ruleset calls use native damage budget 1. This isolates the new native scaling branch from the health/damage outputs; it does not certify the entire committed runtime or establish an exact four-case committed replay. Scratch files were removed. Compatibility pacing was not retuned and the failed expectations remain visible.
## Remaining scope
Off-hand weapon damage, bow/ornament equipment, unknown item effects, unbound Throw, unknown fixed attributes, unrepresented absorb/AoE aura channels and custom gear continue to fail closed. Cross-system incoming-hit aura translation into native source gates, native resource regeneration, full scene navigation and broader encounter balance remain outside this pass. RoM classes remain Needs Testing.
@@ -0,0 +1,111 @@
# RoM native Priest healing source adapter
This is a local RuneWaker source implementation for native RoM healing. It is
not a Chronicles of Arcadia formula, and it does not infer a spell rank from a
source catalog value. `MagicProc.MagicLv` is a required runtime input. The
simulator may explicitly map its trained skill level to
`clamp(characterLevel, 1, 80)`; that is simulator policy, not a claim about the
source database's configured `MagicLV` field.
## Direct HolyHeal
`romNativeHealing.ts` resolves the `MagicProcess.cpp` `AtkCalType::HolyHeal`
branch. The source equation is:
```text
OrgPower = DmgPower + DmgPower * DmgPower_SkillLVArg * MagicLv / 100
SpellTime = MagicCol.SpellTime; use 1 when below 1 or IsFixDmgEffect is true
MNDPart = MND * 0.3 * SpellTime
Power = OrgPower * 6 when OrgPower * 5 < MNDPart; otherwise OrgPower + MNDPart
unless IsIgnoreDmgEffect:
add MDMG * FIX.Dmg_HealArg, once when fixed or multiplied by SpellTime otherwise
Power = Power * MPow * HealPowerRate + HealPoint * SpellTime
per target, apply Atk.Rand variation
unless MagicBase.SettingEx.IgnoreMagicAbsorb:
Power = Power * (1 + HealAbsorbRate / 100) + HealAbsorb
clamp Power below zero; reverse sign for undead; suppress negative undead output out of combat
```
The generated source map binds ability and rank identity to raw `MagicCollect`
rows and direct HP `MagicObject` components. It preserves source component IDs,
`AtkCalType`, signed `DmgPower`, its skill-level argument, fixed fields,
random range, critical rate, `SpellTime`, range/sharing data, and the distinct
`MagicCollect` timing flags and mode flags. `holyHealBindings` is the 18-row
subset with `AtkCalType == 5`; `attackBindings` retains all 225 direct HP
ability rows for shared combat integrations.
The Priest bindings include Heal (`490261`, `DmgPower 90`, argument `30`,
`SpellTime 2`), Group Heal (`490281`, `DmgPower 65`, argument `20`,
`SpellTime 3`), and Urgent Heal (`491147`, `DmgPower 35`, argument `20`,
`SpellTime 1`). Their exact component and rank records are in the generated
metadata. The helper expects already-effective native caster and recipient
channels; callers must not run generic healing modifiers a second time when
those modifiers were included in the effective inputs.
## Periodic HP healing
Runewaker has a separate native HoT path. It is not a HolyHeal cast repeated
each tick. `MagicProcess.cpp` computes the applied buff duration and invokes
`CalAddDotMagicLv`; `RD_Normal.cxx` calculates the buff's source rank
correction; `RD_ValueCal.cxx::BuffProc` uses the frozen `Buff.Power` at each
tick. The helper supports active positive magical `DotMagic` with HP type 0,
including Priest's Regenerate (`490269`). It deliberately returns no result
for unsupported `DotMagic` types, including percentage HP type 5.
At application, the source first derives actual buff duration from
`EffectTime`, `EffectTime_SkillLVArg`, `DLV_EffectTime`, and owner/target
levels, then uses `DotTimes = max(1, int(EffectTime / Dot.Time))`. For a
positive magic HP dot, the source calculates:
```text
DotBase = Dot.Base * (1 + MagicLv * DotSkillLVArg / 100)
ExRate = 0.6 + abs(DotBase) / 600 for an IsPlayer owner; otherwise 1
Power = DotBase + ExRate * MDMG * int(SpellTime) * FIX.Dmg_HealDotArg / DotTimes
MNDPart = MND * 0.3 * int(SpellTime) / DotTimes
Power = Power * 6 when Power * 5 < MNDPart; otherwise Power + MNDPart
Power = Power * HealPowerRate + HealPoint * int(SpellTime) / DotTimes
unless IgnoreMagicAbsorb:
Power = Power * (1 + HealAbsorbRate / 100) + HealAbsorb / DotTimes
clamp Power below zero; Power *= MagicPow(MagicType)
MagicLvAdjustment = int((Power - Dot.Base) / (Dot.Base * DotSkillLVArg / 100) - MagicLv)
Buff.Power = MagicLvAdjustment + MagicLv
```
`FixDotPower` or a zero `DotSkillLVArg` bypasses the rank correction, leaving
`Buff.Power = MagicLv`. The source tick then computes
`Damage = int(-Dot.Base * (100 + DotSkillLVArg * Buff.Power) / 100)` and applies
`AddHP(-Damage)`. C++ integer conversion truncates toward zero. Recipient
absorb and caster channels are captured through the buff-rank correction at
application; the source does not reapply them on each tick. The helper returns
the resulting integer tick amount and the `DotTimes` interval count so the
runtime can preserve that application snapshot.
The live helper requires an explicit effective
`MagicPow(MagicType)` value. The existing native stat sidecar has an all-magic
neutral MPow channel but does not expose all six element-specific MPow
`BodyRate` channels. The caller must supply an effective source value when
element-specific modifiers are modeled. For this simulator's active
player-build identities, `sourceIsPlayer=true` is an explicit policy applied
to both the active player and party companions; the original `IsPlayer()` test
itself distinguishes actual server player roles.
The current Priest Regenerate source row contains positive HP DotMagic
components `500469` (argument 18), `621318` (argument 18), and `621548`
(argument 25). They share `Dot.Time 2`, `Dot.Base 20`, and duration 20 seconds.
The generated map retains each component ID so the runtime can use the
component selected by its own source semantics instead of guessing which raw
component is active.
## Source snapshot and limits
The generated artifact is
`src/game/generated/romNativeHolyHealBindings.generated.json`; regenerate it
with `scripts/runewaker-pipeline/export-rom-native-healing.mjs`. It is tied to
the current hashes of `magiccollectobject.db`, `magicobject.db`, the local
server formula files, the player catalog, and generated native stat rules.
The output includes 225 direct-attack ability rows, 18 HolyHeal ability rows,
and 8 positive magical HP DotMagic ability rows across the catalog.
The data and formula boundary is the local RuneWaker source version hashed in
that artifact. This work does not add CoA rank data, model percentage HP
periodics, or infer unavailable source skill levels from `configuredCollectMagicLevel`.
@@ -0,0 +1,33 @@
# Native RoM level-one boss pacing — 2026-10-03
## Adjustment
The native RoM health policy now uses a `0.20` boss-health scale at character level 1, down from `0.30`. The level-1 trash scale remains `0.40`. Every health anchor at level 10 and above is unchanged, as are all `nativeDamageBudgetScale` anchors. The level-1 boss value interpolates linearly to the existing level-10 boss value, so native bosses at levels 2–9 also receive the corresponding smooth interpolation. This is a simulator health budget for the targeted five-build cohort, not a RuneWaker source monster-health formula.
The adjustment followed source recovery and the separately implemented level-one Priest mana reserve. With the previous `0.30` boss value, the level-one native Knight diagnostic still ended with actor deaths; the reported pull had 391.2 incoming damage and 56 healing. The authorized retune changed only the level-one boss-health anchor.
## Five-build result
The unchanged 80-pull native rotation diagnostic passed at the `0.20` anchor. It covers each of the five identities as the active character and four native companions against Barren Caves trash and Anglo at levels 1, 10, 30, 60, 65, 66, 79, and 80. All 80 targets died; every player survived, no companion died, every native combatant was supported, and there were no invalid cast failures. This is a fixed-position simulator diagnostic, not scene navigation or a readiness promotion.
The pair names below identify each configured build; at level 1, secondary classes are inactive, so these five samples all use pre-secondary snapshots. They all used the same 1,848-HP budget and had no player or companion deaths:
| Active build | Clear after first party hit | Player HP remaining |
| --- | ---: | ---: |
| Knight/Scout | 42.1s | 95.6 |
| Priest/Knight | 34.1s | 152.4 |
| Rogue/Warrior | 36.9s | 129.6 |
| Scout/Rogue | 39.7s | 120.4 |
| Mage/Warlock | 34.1s | 142 |
The complete generated diagnostic is `artifacts/rom-five-native-rotation/report.json`. `romNativeDungeonPacing.test.ts` now locks the level-one Anglo value at 1,848, verifies that level-one native trash remains at the unchanged 0.40 ratio, and checks the unchanged damage budget. The level-80 native health plateau/cap assertion remains exact and unchanged.
## Interpolation and boundaries
The new level-1 boss anchor changes the interpolated native level-8 Stockades regression from 8,330.293333 to 7,983.197778. Its expectation was updated to the computed interpolation; the native level-80 Stockades health remains 1,312,656 with damage-budget scale 40. The legacy WoW-stat RoM pacing curve and its mixed-mode harness are unchanged.
No trash-health anchor, level-10-or-higher health anchor, native damage-budget anchor, authored damage multiplier, source enemy damage, equipment, loot, level cap, actor mode, or Ready-party policy changed. This calibration does not claim a complete early-level balance pass or readiness status.
## Validation
Focused verification passed `romNativeDungeonPacing.test.ts` and the unchanged `romFiveNativeRotation.integration.test.ts`: 6 tests total, including 80 pulls. The level-one five-build results and full diagnostic metadata are archived in `artifacts/rom-five-native-rotation/report.json`. The post-recovery legacy boss pacing suite passed 18/18 tests; its 83-sample report is archived at `artifacts/rom-enemy-followup/after-compatibility-pacing-post-recovery.json`.
@@ -0,0 +1,35 @@
# Native RoM NPC Equipment Coverage Completion — 2026-10-03
## Result
The native NPC equipment resolver now supports all 440 generated source NPCs under the default deterministic selection and every explicit main-hand/off-hand candidate pair: 440 defaults plus 11,000 candidate-pair snapshots (25 per NPC). The five source candidates and their 20% weights are preserved; the resolver still chooses one reproducible candidate rather than averaging equipment.
The pre-change audit reported 398/440 supported default selections. Its remaining unresolved groups were off-hand weapon DMG, fixed BowEQ channels, two nonzero values tagged `EM_WearEqType_None` on item 211800, and four valid but mismatched vocation/sub-vocation IDs. Some of the gear reasons overlapped on the same NPC. After the changes, those 42 default fallbacks are resolved.
## Source-backed channels
`RoleAttr.cpp::AddAbility` routes type 25 to `BaseEQ.Main_DMG`, `BaseEQ.Sec_DMG`, or `BaseEQ.Bow_DMG` according to the main-hand, second-hand, or bow position (lines 1323, 1479, 1627). Type 25 on armor remains a generic body DMG contribution. The resolver now preserves the three weapon-position amounts independently and applies the NPC second-hand `Dmg_SecHand` coefficient when it produces `offHandDamage`. `RoleAttr.cpp::_SecDMG` defines that coefficient and its damage inputs (lines 766–806); `_Bow_DMG` defines the bow amount (lines 1124–1139). The generated NPC FixTable value for `Dmg_SecHand` is 0.7.
Selected off-hand and bow weapons also expose their source attack speed and range. Recognized armor type-23 attack-speed effects are applied to each weapon speed channel. A type-23 effect on an off-hand or bow weapon remains fail-closed because its position-specific behavior has not been established. Type 191 continues through the existing generic MDMG channel. No current imported NPC has an ornament item; any future non-empty ornament remains fail-closed until its slot-specific path is verified.
The source enum identifies wear index 0 as `EM_WearEqType_None` (`ObjectStruct.h:1427`). The two value-35 pairs on item 211800 are therefore treated as no-op channels, while the item's type-25 and type-191 rows continue to contribute normally. Its drop-ability metadata remains metadata and is not applied as an equipment affix.
Across all five choices for all 440 NPC records, the active effects are type 0, 3, 5, 8, 12, 13, 14, 22, 25, 150, and 191. No current NPC equipment record has an ornament item. Ten records have BowEQ, all now supported. Unknown nonzero wear types remain fail-closed; the resolver does not infer future effects from these present-day counts.
## NPC sub-vocation growth
The four corrected source identities are NPCs 100074 (vocation 4/sub 6), 100594 (6/1), 100611 (0/6), and 100614 (0/6). `RD_ValueCal.cxx::InitCal` clears a duplicate primary/secondary vocation (lines 114–118), then assigns a valid NPC `Level_Sub` from its primary level (lines 154–161). `RoleAttr.cpp` adds one tenth of the secondary vocation's full race/vocation/sex base curve for each base attribute and for HP/MP (lines 96–124). The resolver now applies that one-tenth curve to the five exposed attributes and derived HP. Primary vocation coefficients and damage rate stay primary-vocation values, matching the source's separate primary `Arg` path. Sub-vocation mana is not exposed by this NPC combat snapshot.
The regression test locks each corrected NPC's resulting five attributes and health to its source-derived values. NPC recovery inputs are not part of this change.
## Resolver API and limits
`romNativeNpcCombatant(npcId, runtimeLevel, equipmentSelection)` remains the integration entry point. Its result includes the exact `equipment` choice and selected candidate indexes. The outer result now has optional `offHandDamage`, `offHandAttackSpeed`, `offHandAttackRange`, `bowDamage`, `bowAttackSpeed`, and `bowAttackRange` fields when those source weapons are present. The embedded `nativeCombatant` and periodic snapshot stay separate from encounter health/damage budgets.
The fixed-bow rows currently have neutral source rate factors for all non-target bow modifiers. Rate effects that are not represented by the current equipment catalog remain unsupported and fail-closed if they occur. This pass does not wire equipment fields into combat scheduling, change authored loot, or alter player-stat resolution.
## Validation
Focused validation: `npx vitest run src/game/romNativeCombatResolution.test.ts src/game/romNativeNpcEquipment.test.ts` — 2 files and 18 tests passed. The population regression checks all 440 default records and all 11,000 explicit candidate-pair selections.
Read-only source references are under `F:\Projects\Runewaker\SourceCodeVS2019\Libraries\Union\RoleData`: `ObjectStruct.h`, `RD_Setting.cxx`, `RoleAttr.cpp`, and `RD_ValueCal.cxx`. The generated NPC equipment catalog already contains the required source candidate and item rows, so this completion needed no exporter or generated-data change.
@@ -0,0 +1,62 @@
# Native RoM NPC equipment pass — 2026-10-03
## Scope and behavior
This pass adds source-backed NPC WearEQ effects to the native Runewaker combatant path, capped at the repository's existing supported level 80. It does not connect equipment drops or loot. The WoW path and per-actor combat modes are unchanged.
The `export-rom-native-npc-equipment.mjs` exporter reads the NPC candidate lists and fixed BowEQ/OrnamentEQ values from `npcobject.db`, referenced rows from `weaponobject.db`/`armorobject.db`, and refine rows from `eqrefineabilityobject.db`. It preserves all five NPC main-hand/off-hand candidate slots at 20% each, including duplicate and empty choices. Runtime resolution is deterministic and does not average candidate stats:
```ts
romNativeNpcCombatant(npcId, runtimeLevel, {
selectionSeed: stableActorOrEntityId,
// Optional source candidate overrides:
mainHandCandidateIndex,
offHandCandidateIndex,
});
```
Use an actor-unique stable seed when separate live copies of one NPC should roll independently but reproducibly. Omitting the seed defaults to `npcId`; supplying a candidate index pins that source slot. The resolved equipment and selected candidate indices are included in the combatant result.
The source NPC spawn initialization sets item count to one, durability to 10000, quality to 100, power quality to 10, rare to zero, and item level to `min(RefineLv, 20)`, while selecting the main-hand candidate with `rand() % _MAX_NPC_EQSEL_COUNT_` (`RD_Setting.cxx:2671–2681`). `WearEQ` computes durability power tiers and applies power quality (`RD_ValueCal.cxx:1138–1167`), reads weapon attack range/speed and main-hand values (`1186–1194`), then applies refine rows and the rare-dependent extra-equipment rate (`1212–1272`). Refine lookup is item refine-table ID plus level minus one (`3743+`). These source paths drive the exported defaults, equipment choice, wear power, item weapon speed/range, and refine contributions.
Known nonzero `WearEqType` values are translated only where the existing native snapshot has a source channel: attributes and rates, max HP, physical/magical attack and defense, hit/dodge/critical/parry, main-hand attack speed and damage, body physical damage, magic damage, healing, resistance amounts/rates, and typed magic-power rates. The enum identifiers/order are in `ObjectStruct.h:1425+`; `RoleAttr.cpp` verifies base main-hand speed 30, final DMG/MDMG/main damage, and the separate Throw_DMG calculation (`184`, `288–314`, `645`, `655`, `713`, `1201–1204`). `nativeCombatant.throwDamage` carries the derived neutral Throw_DMG input for exact source skill formulas that require it. Unknown nonzero types fail closed. Drop ability IDs/rates are kept as explicitly named drop metadata and are not applied as wearable stats.
## Coverage and limits
The imported population has 440 NPC rows. Under the stable default NPC-id seed, 398 resolve to a supported native snapshot. The remaining 42 do not silently receive neutral equipment: 26 selected off-hand weapon damage cases lack a modeled secondary-weapon damage channel; 10 rows have BowEQ/OrnamentEQ channels not represented by the current snapshot; two rows select item 211800 with unknown nonzero WearEqType 0/value 35; and four NPCs (100074, 100594, 100611, 100614) have a vocation-sub-ID mismatch that prevents deriving the existing native stats snapshot.
Across the 112 distinct referenced equipment items, no item ID is missing. There are 96 items with nonzero WearEQ ability entries; 95 have fully mapped active entries, while one has the unresolved type 0 entry above. Referenced source item effect types are 3 (STA), 5 (MND), 8 (MaxHP), 12 (ATK), 13 (DEF), 14 (MDEF), 22 (parry), 25 (DMG), 150 (HealPoint), and 191 (MDMG), in addition to zero/empty slots. The resolver also implements the additional enum channels listed above for source completeness, but does not claim every enum has been validated against a currently equipped item. Twenty-two items have nonzero `DropItemAbility` metadata; those records are not WearEQ affixes and are not wired here.
The exporter captures refine metadata and the resolver applies a verified refine row sequence when an imported item has a refine level. Current referenced NPC gear has no item with a positive refine level, so the refine application branch is source-implemented but not exercised by present population data. Inherent attributes and runes are empty in the source NPC spawn defaults. Bow/ornament wearable effects and off-hand weapon DMG/speed remain unsupported at combatant construction; no unknown effects are discarded. The source factory's four vocation-sub-ID mismatches remain unchanged by this equipment pass.
The Barren Caves targets are supported with their exact source equipment outcomes:
| NPC | Source equipment | Source durable / attack speed | Resolved wear power |
| --- | --- | --- | ---: |
| 101459 | Main hand 210056 | 70 / 20 | 1.2 |
| 101460 | Main hand 210061 | 55 / 20 | 1.2 |
| 101461 | Off hand 210666 | 1426 / 20 | 0.2 |
These items have no active WearEQ ability entries, so they preserve the source neutral combat stats while replacing the previous neutral main-hand speed fallback of 30 only when a real source weapon provides its own speed. An independent positive-effect check covers item 210048 (NPC 100606, main-hand candidate 0): source DMG 213 and MDMG 167 contribute at the source 1.2 wear power. NPC 106315/item 213019 also verifies STA, parry and low durability power (0.2).
## Generated source snapshot
`src/game/generated/romNativeNpcEquipment.generated.json` is tied to these local source hashes:
| File | SHA-256 |
| --- | --- |
| `npcobject.db` | `b627b6eb269c30576a6558000a31abe2db472689ef9a60cc1c1e20207abd69f1` |
| `armorobject.db` | `ccdd438219b801680e4f7c8354171d5347dcab5fcf581f554c39eba3543d961a` |
| `weaponobject.db` | `ca58aa607388c4df2fc1a5c6030b1552c2eecb90082fe381cd836aabf6fe467b` |
| `eqrefineabilityobject.db` | `724a469d095466df55eb72264ee746a9c6fca866eb76fcb500270cfee3d02f43` |
## Validation
Focused tests run:
```text
npx vitest run src/game/romNativeNpcEquipment.test.ts src/game/romNativeCombatResolution.test.ts
16 tests passed
```
The tests preserve the Barren candidate arrays and weights, check deterministic and explicit candidate selection, check exact item WearEQ power, verify mapped nonzero DMG/MDMG and attributes/parry effects, ensure unknown effects fail closed, and assert that bow/ornament and invalid candidate paths remain unsupported. Broader app validation is handled by the parent integration task.
@@ -0,0 +1,19 @@
# RoM native party selection (2026-10-04)
## Finding and owner
`src/game/partyStore.ts` owns live companion selection. It previously shuffled the fixed native-five pools by role without receiving the player's active class pair. In a full Stockade party with Scout/Rogue in the damage seat, the three-candidate damage pool could therefore select Scout/Rogue again and omit Mage/Warlock. The Knight/Scout tank fixture happened to be valid because the fixed role pools did not repeat its tank identity.
`src/game/PartyBridge.tsx` now passes the active profile's ordered RoM pair into generation. `src/ui/ManastormSelectScreen.tsx` passes the same pair to avatar preloading so its preview uses the same party as entry.
## Selection contract
When the player pair exactly matches one of the five canonical identities, generation excludes that identity only if the remaining identities can satisfy every requested NPC role seat. This preserves the exact native complement for all five supported player pairs and keeps role assignment intact. If the pair is outside the active five, lacks a secondary class, or cannot satisfy the requested role counts, generation uses its prior per-role shuffled pool.
The option is read only for `categoryId === "rom"`. It does not alter any member's stat ruleset, expand the native pool, affect WoW specialization readiness, or change explicitly configured companions. Party resets retain the same option through the existing `PartyState.companionOptions` lifecycle. RoM identities remain separate from WoW eligibility and online specialization filters.
## Focused validation
`npm test -- --run src/game/partyStore.test.ts` passed: 32 tests in one file. New checks verify the exact unique four-identity complement, canonical names and roles, and native RoM stats for each of the five player pairs. Fallback checks cover an unsupported pair, a role composition the complement cannot fill, and WoW generation with a RoM pair option.
The parent task completed the shared build and bounded Stockade checks of both normally generated entry complements; see [the coordinated report](ROM_HEALING_PARTY_RANGED_FOLLOWUP_2026-10-04.md). No other repository tests, balance sweeps, full-suite run, build, staging, or commit were performed by this subtask. Work stayed in the existing `main` checkout.
@@ -0,0 +1,31 @@
# RoM native periodic damage source pass — 2026-10-03
This pass adds a source-bound first-application snapshot and per-tick amount helper for negative HP `DotMagic` effects. It covers the active five RoM builds and deliberately leaves resource drains, healing-over-time, positive-base effects, unsupported refresh behavior, and unverified NPC stat derivation to their separate paths.
The exporter reads the sibling `Runewaker` tree without modifying it. `scripts/runewaker-pipeline/export-rom-native-periodic-damage.mjs` binds exact `MagicCollect` skill IDs to the active player catalog and imported NPC combat profiles, then emits `src/game/generated/romNativePeriodicDamageBindings.generated.json`. The active five contribute 18 ability rows, 18 source-rank rows, and 14 unique negative HP/HP_Per DotMagic components. The imported NPC source table has 440 NPC rows and 446 population-entity mappings; 50 NPCs currently have bound negative HP/HP_Per DotMagic, with 50 source-rank rows and 42 unique components. The union has 56 unique component IDs. NPC tick sources preserve the assigned slot MagicLv and use the verified native NPC growth upper bound of 200; this does not imply that every NPC stat profile is ready for native resolution. The JSON records the raw source IDs, selected fields, filter, record offsets, and SHA-256 hashes for the source databases/code and local catalogs.
## Application and tick order
`MagicProcess.cpp` passes the effective cast `SpellTime` and `MagicProc.MagicLv` to `CalAddDotMagicLv` when applying an assist effect. The rank helper uses `DotTimes = max(1, int(MagicBase.EffectTime / Dot.Time))` from the raw MagicBase duration; this is distinct from the effect duration later computed for the applied buff. For a negative HP DotMagic row, the correction first builds `DotBasePower = Dot.Base * (1 + MagicLv * DotSkillLVArg / 100)`. `FixDotPower` returns no correction, and a zero `DotSkillLVArg` also returns no correction.
For magical effects the source adds or subtracts caster MDMG scaled by the player/NPC `ExRate`, cast `SpellTime`, `FIX.MDmg_DotArg`, and `DotTimes`. If the resulting power is negative, the source applies the target's `CalResistDMG` to the aggregate power across `DotTimes`, divides back by `DotTimes`, then applies the source `(MATK + 100)/(MDEF + 200)` power rate. If it becomes nonnegative, it enters the source heal-power branch and multiplies by `MagicPow(MagicType)`. Physical effects instead use `Main_DMG`, `Main_ATKSpeed`, `FIX.MDmg_DotArg`, and `(ATK + 100)/(DEF + 200)`; they do not call magical resistance. The returned correction is `int((FinDmg - Dot.Base) / (Dot.Base * DotSkillLVArg / 100) - OrgMagicLv)`.
`MagicProcess` adds this correction to the cast's `MagicLv`, then forces it to zero when `ShowPowerLv` is set. It computes applied duration from the base effect time, effect-time skill argument, and caster-target level difference. `AssistMagic` then applies the source maximum-skill-level and `BuffMaxLv` caps. The helper requires the actual effective `MagicLv`, caster and target levels, and exact source-derived combatant inputs instead of guessing a spell rank or a missing weapon/resistance value.
`RD_ValueCal.cxx::BuffProc` emits a tick when elapsed buff time is divisible by `Dot.Time`. Each tick starts with `int(-Dot.Base * (100 + DotSkillLVArg * Buff.Power) / 100)`. `HP_Per` then multiplies by the target's current `Fin.MaxHP / 100` and truncates again. The source dispatches its periodic special-attack event before the PK adjustment and HP shield/HP application; magical DoTs use the `magic` event and physical DoTs use the `skill` event. `MagicShieldAbsorbProc` runs before HP application. `DotMagicNoKill` keeps the target at 1 HP when applicable. The tick reuses stored `Buff.Power`: it does not reroll a critical hit or reapply armor/resistance. The pure tick helper returns the integer amount and event/no-kill metadata; the shared combat runtime remains responsible for shields, health application, and side effects.
The runtime API in `src/game/romNativePeriodicDamage.ts` separates application snapshot inputs from tick inputs. Elemental magical rank correction requires the target's exact resistance channels and caster's effective `MagicPow(MagicType)`. Physical rank correction requires exact `Main_DMG` and `Main_ATKSpeed`. NPC callers must provide the NPC's exact `FIX.MDmg_DotArg` and source-bounded caster/MagicLv limits; only the source player value is taken from generated verified rules. Player builds remain capped at level 80. Enemy lookup accepts the MagicCollect `spellId` and exact component ID, and the NPC source list is limited to imported encounter NPC spell bindings. An existing-stack reapplication is unsupported because `AssistMagic` can retain or raise the existing buff power. Unsupported inputs return a reason rather than a substitute amount.
## Active-five special fixed inputs
The active-five direct-damage binding audit found 66 negative `Attack.DmgPower` components. Of these, four use fixed type 4 (`Throw`): Rogue source skills 490338 and 490309, components 502578 and 620283, each with `FixValue=-3`. Three use fixed type 12 (`ShieldDef`): Knight skill 490175/component 500175 and skill 490186/components 500177 and 500185, each with `FixValue=-0.1`. No active-five negative direct component uses type 10 (`LastSkillDmg`), type 11 (`LastPhyDmg`), or the separate calculation-type Throw branch.
`MagicProcess.cpp` evaluates each fixed input as `Owner->GetValue(FixType)`, so the fixed source belongs to the caster. `RD_ValueCal.cxx::GetValue` resolves type 4 to caster `Fin.Throw_DMG`, type 10 to caster `BackInfo.LastSkillHitPoint`, type 11 to caster `BackInfo.LastPhyHitPoint`, and type 12 to caster raw `BaseEQ.Def[EM_Armor_Shield]` (not the target's shield or total defense).
`RoleAttr.cpp::_Throw_DMG()` is `max(0, (Fin.DMG + BaseEQ.Throw_DMG) * BaseEQ.Throw_DMG_Per * BodyRate.DMG_AllRange * BodyRate.DMG_Per)`. Without throw equipment, source initialization leaves `BaseEQ.Throw_DMG=0` and `Throw_DMG_Per=1`, but `Fin.DMG` itself already applies its DMG_Per factor, and `_Throw_DMG` applies DMG_Per once more plus the AllRange factor. A single generic physical-damage stat is therefore not enough to derive this input. Runtime should supply verified caster `Fin.Throw_DMG` explicitly or leave these four components unsupported.
Last-hit channels are per caster. `MagicProcess` clears `LastSkillHitPoint` at cast start and sets it from signed `int(Temp.Value)` after supported skill effects. The auto-attack scheduler clears `LastPhyHitPoint` before the attack sequence and stores `Damage * -1` after each attack. Since neither type occurs in the active-five negative direct bindings, no persistent prior-hit channel is needed for those current rows.
## Focused validation
`src/game/romNativePeriodicDamage.test.ts` checks source lookup, magical and physical rank correction, cast duration versus raw rank-correction duration, fixed/show-power rows, HP_Per tick scaling, no tick-time critical reroll, fail-closed inputs, and reapplication handling. `src/game/romNativePeriodicCombat.integration.test.ts` exercises a real player Vampire Arrows application, an active-five Priest/Knight Bone Chill companion application with native magical defense/resistance and the required typed MagicPower inputs, per-actor RoM versus WoW fallback, and an imported NPC HP_Per DoT whose later tick reads the target's current MaxHP. The focused helper/integration command passed all five tests.
@@ -0,0 +1,68 @@
# Native RoM recovery, equipment and pacing follow-up — 2026-10-03
## Source recovery
Native player and owned-party NPC HP/Mana now use the verified RuneWaker ReHP/ReMP inputs. Each actor keeps its own ruleset, attributes, gear and secondary class; saved WoW-mode RoM profiles keep compatibility behavior. Player pulses occur every two seconds, owned NPC pulses every six. Combat recovers no HP and ReMP/24 Mana per pulse; idle standing players use ReHP/ReMP divided by three and idle owned NPCs use 0.66 times those values. Source aura effects are sampled at each pulse, including expiry boundaries. Explicit periodic Mana effects remain separate.
The source audit and limitations are in [the recovery report](ROM_NATIVE_RECOVERY_SOURCE_2026-10-03.md). There is no sitting control or simulator StopOntimeCure state, and combat detection approximates the source attack-mode flag. Stopping companions while an enemy remains engaged does not grant idle recovery.
All five active native companion identities, secondary Mana, and WoW compatibility are covered by `romNativeRecoveryParity.integration.test.ts`. The original focused recovery selection passed nine tests; the additional parity selection passed three.
## Imported NPC equipment
All 440 imported NPC defaults and 11,000 explicit main-hand/off-hand candidate pairs now resolve supported native snapshots. This closes the previous 42 default fallbacks with source position-specific weapon channels, the explicit type-zero no-op, and valid secondary vocation growth. Unknown effects and future non-empty ornaments remain fail-closed.
Off-hand and bow damage/speed/range are available in snapshots; this does not schedule extra enemy swings. No exporter changes or loot wiring were needed. See [equipment completion](ROM_NATIVE_NPC_EQUIPMENT_COMPLETION_2026-10-03.md).
## Compatibility pacing
The four legacy failures are resolved with boss health budgets while retaining the original 25-second ordinary and 45-second final minimum checks. WoW starter health floors are 1,800 at enemy level 2 and 2,600 at level 4. RoM-origin WoW-mode boss health has a separate compatibility multiplier. Native source amounts and actor defaults remain independent.
All 83 targeted compatibility timing samples now pass, including all 12 level-80 RoM seeds. The focused scaling selection passed 18 tests and the additional native/bite-sized pacing selection passed six. Exact native level-8 and level-80 health/damage-budget assertions guard separation. Full pre/post timing evidence is in [the pacing report](LEGACY_BOSS_PACING_FIX_2026-10-03.md).
## Source recovery pressure measurements
Six focused pressure tests passed, including 16 real-source Anglo pulls at levels 10/30/60/80 with scripted spread/stack positions, active/idle healer comparisons, movement, interrupts and player/NPC dispels. All sixteen pulls clear without deaths. Native source recovery lowers minimum active-healer Mana at level 10 from approximately 95–97% to 77–85%, and at level 30 from 96% to 87–90%. Levels 60/80 still retain approximately 98–99% Mana. This records the remaining high-level sustain limitation instead of claiming a challenging Mana budget across all levels.
Reports are preserved under `artifacts/rom-enemy-followup/`; these artifacts are diagnostics rather than readiness certification. The historical 80-pull cohort used shared regeneration. Its clear times cannot establish current native source sustain.
## Early-level sustain correction
The source-recovery rerun exposed a real early-level regression: the level-one Knight/Anglo sample took 141 seconds with a player and Rogue NPC death, compared with the preserved 54-second shared-regeneration baseline. Holy Strike's manual effect rewrite had lost its weapon delivery classification, so its Holy school prevented starting free auto-attacks. Explicit source attack-kind metadata now preserves the same 16-point Holy direct hit while starting the 22-point physical training swing. The focused cast-to-auto regression passes; no weapon-hand amount override or source recovery multiplier is used to hide the issue.
The level-one NPC Priest has 123 Mana and ReMP 4.8, recovering only 0.2 Mana per six-second combat pulse. Its shared fallback initially chooses 12-Mana Rising Tide while Urgent Heal costs 25. The early native-healer decision policy reserves one learned direct heal before spending Mana on hostile damage. This is a clean-room simulator rotation policy, separate from source recovery and spell amounts.
The reserve preserves its spending boundary; it does not by itself resolve the failed fight. After both runtime fixes, the 0.30 native level-one boss factor still kills the Knight and Rogue NPC. The measured training budget is now 0.20 at level one, leaving trash at 0.40 and every anchor from level 10 onward unchanged. Levels 2–9 interpolate smoothly to the unchanged level-10 factor. Anglo's level-one pool becomes 1,848 HP; the Knight clears in 42.1 seconds with 95.6 HP and no companion deaths. The five level-one player seats clear Anglo in 34.1–42.1 seconds. Source recovery, damage formulas and damage-budget anchors remain unchanged.
The unchanged fixed diagnostic now passes all 80 player/four-NPC pulls at levels 1/10/30/60/65/66/79/80: zero player/NPC deaths and zero invalid casts. Trash takes 4.9–8.7 seconds and Anglo 34.1–58.5 seconds. Static positions do not establish full scene navigation.
## Focused verification
The final source/recovery/resource/damage-type selection passes 156 tests across 24 files, including all 40 fixed/MaxHP actor cases and the 16-pull pressure report. The separate 80-pull diagnostic and five native pacing checks pass. The exact legacy suite passes all 18 checks again after the source-recovery and reserve changes; its 83-sample final report is `artifacts/rom-enemy-followup/after-compatibility-pacing-post-recovery.json`. Ready-five passes seven Vitest and twenty Python cases; avatar checks pass 47 tests. These selections overlap and should not be added as unique test counts.
An additional `combatRotation.test.ts` run passes 30 of 31 checks. Its existing representative-signature assertion fails for Rogue Killing Spree because that catalog entry has only unsupported/scripted/utility effects. The assertion does not exercise the new native reserve; this unrelated mechanic was not implemented or its check weakened. The four new reserve checks pass, including the real benchmark fallback gate, exact 36/37-Mana boundary, effective-cost override and valid/invalid heal targets.
The 8 GB app TypeScript check and final `npm run build` pass, including bootstrap generation, texture/performance audits, TypeScript/Vite, static compression and release-bundle verification. The performance audit reports no new regressions; existing chunk-size and static/dynamic-import warnings remain. Final chunks are `index-DzLgXnx0.js`, `combatStore-Dh-12M9R.js`, `GameRuntime-C95Du8PI.js` and `PartyFrames-Cf7FSiBA.js`.
## Full selected production encounters
`scripts/playtest-native-combat.cjs --full-fights` uses an isolated local account and the exact final production build. A UI-created level-30 native Priest/Knight healer joins the four other native identities. The selected Boss Testing scenes keep original attack lists/cooldowns; level and class pairing are test setup. Keyboard action bindings perform healing, cleanses and counters without direct damage, HP/Mana or healing edits during fights. These reduced testing-room budgets are separate from campaign durability.
| Selected scene | Clear time | Player Mana minimum / end | Survival |
| --- | ---: | ---: | --- |
| Anglo, RuneWaker NPC 101462 | 39.9s | 88.7% / 88.9% | Player and all four NPCs alive |
| Lady Anacondra, WoW creature 3671 | 16.5s | 91.0% / 91.0% | Player and all four NPCs alive |
There are no page errors. Anglo retains Physical Trample/Bash and its magic-dispellable Gulp control; Lady retains Nature-school spell Lightning Bolt and her original Druid's Slumber. Source-ID namespaces remain separate. Both Anglo cast cancellations were observed before their scheduled completion alongside real healer counter inputs. Gulp clears from the tank 1.85 seconds before source expiry after a cleanse input; the Rogue's separate Gulp expires naturally. Lady's Mage sleep clears 4.74 seconds before expiry after a cleanse input. Lady's single Vow of Silence attempt did not show a Lightning Bolt cancellation, so this run does not establish that particular cross-source interrupt behavior.
The full fights record zero movement inputs; the ranged healer remains outside the melee warning. Movement is checked separately in a labeled staged source-warning fixture, rather than being attributed to those full fights.
The same-final-build staged Anglo selection passes all three source fixtures, each releasing once, with no page errors. Trample spell 492292 retains its 1.8-second cast, five-unit radius, Physical school, effect and warning. Fixture setup selects one source attack, resets readiness/positions/threat and sets repeat cooldown to 60 seconds; companion actions are paused for the movement warning. Real W-key movement covers 2.75 units while the cast remains live, from 3.93 inside the radius to 6.69 outside. The player receives zero Trample damage while a nearby Rogue receives 262, proving recipient exclusion rather than suppressing the entire packet. Bash and Gulp also release once. Telemetry is `playtest-artifacts/native-combat/results.json`; the warning and movement images are `anglo-trample-warning-fixture.png` and `anglo-trample-movement-fixture.png`. Both were visually reviewed.
Full-fight telemetry and screenshots are in `playtest-artifacts/native-combat/full-fights-20261004-024033763/`. Root visual review confirms the roster player's body/staff, loaded player and party bodies with held weapon/shield/staff/bow silhouettes in the mid-fight capture, readable native recovery/Training gear equipment UI, and the defeated-boss result. Initial NPC loading placeholders resolve by mid-fight; they are not claimed as the loaded visual proof. No readiness review or dungeon report was submitted.
The harness syntax check, repository release check (including untracked files), repository/vault diff checks and edited-vault-note EOF/whitespace checks pass. These selected desktop Boss Testing scenes and scripted diagnostics do not certify every encounter, mobile UI, campaign traversal or readiness.
## Validation boundary
This is targeted work on the five active RoM builds and the current WoW Ready five. RoM builds remain Needs Testing. Cap 80, actor-local compatibility switching, automatic Training gear and the current loot scope remain unchanged. No all-class sweep, readiness promotion, commit or deployment is part of this task.
@@ -0,0 +1,40 @@
# Native RoM recovery source audit
## Implemented scope
Native RoM recovery now uses RuneWaker's ReHP/ReMP values and actor-specific pulse cadence for exact RoM-mode player builds and owned party NPCs. Player and companion stats remain actor-local: a companion uses its own class, secondary class, level, race, gear, and `statRuleset`. The native path only activates for a RoM class whose actor ruleset is `rom`; saved WoW-mode RoM characters and ordinary WoW actors keep the existing shared resource behavior.
The source-derived stat snapshot is already generated by `scripts/runewaker-pipeline/export-rom-native-stat-rules.mjs` into `src/game/generated/romNativeStatRules.generated.json`. `src/game/romNativeStats.ts` computes ReHP from its source base, stamina coefficient, and mapped gear/aura channel; ReMP uses its source base, wisdom coefficient, and mapped gear/aura channel. The five active build stat profiles use BaseReHP 2, ReHpArg 0.15, BaseReMP 0, and ReMpArg 0.3. The character's supported Mana eligibility is preserved, including a Mana secondary pool when the selected primary resource is not Mana.
## Source behavior
`F:/Projects/Runewaker/SourceCodeVS2019/Server/NetGameServer/MainProc/Global.cpp` contains the source player update at lines 1956–1984 and owned-NPC update at lines 2335–2363. Player recovery checks every `ClockMod(20)` and owned NPC recovery every `ClockMod(60)`, corresponding to 2-second and 6-second pulses in the source server clock. Dead actors and actors with `StopOntimeCure` set are skipped. Recovery only runs when integer current HP or MP differs from its maximum.
For players, `IsAttackMode()` restores no HP and restores `ReMP / 24` Mana per pulse. Out of attack mode, standing recovery restores `ReHP / 3` and `ReMP / 3`; sitting uses `0.66 * ReHP` and `0.66 * ReMP`. For owned NPCs, attack mode likewise restores only `ReMP / 24`; idle recovery restores `0.66 * ReHP` and `0.66 * ReMP`. The separate unowned-NPC branch uses max-resource fractions and is not the source behavior for party companions.
`F:/Projects/Runewaker/SourceCodeVS2019/Libraries/Union/RoleData/RoleAttr.cpp` lines 525–531 defines:
```text
ReHP = max(0, BaseReHP + Fin.STA * ReHpArg + Mid.Body[ReHP])
ReMP = max(0, BaseReMP + Fin.MND * ReMpArg + Mid.Body[ReMP])
```
The resulting values are copied to `Fin.ReHP` and `Fin.ReMP` in the same file at lines 279–280. `RD_ValueCal.cxx` lines 1512–1552 (`AddHP`) and 1584 onward (`AddMP`) apply float amounts to the stored resources and clamp to their maxima, so simulator pulse values remain fractional instead of being rounded to whole points.
RoM Aura components mapped to source ReHP/ReMP channels are included in the per-pulse source stat snapshot. Other generic or unmarked regeneration modifiers do not enter the native recovery calculation. Explicit `rom-resource-over-time-*` Mana effects remain a separate simulator flow and are integrated over the effect's actual active interval; they are not added to ReMP. WoW's five-second mana spending rule and out-of-combat minimum do not apply to the native ReMP path.
## Runtime ownership and validation
`src/game/romNativeRecovery.ts` owns the 2-second player and 6-second owned-NPC pulse clocks, fractional source formulas, sitting coefficient, and separate explicit periodic-Mana interval integration. The clocks preserve fractional elapsed time across update partitioning and clear when actor kind/ruleset changes. `src/game/combatStore.ts` owns the player pulse consumer; `src/game/partyRuntime.ts` owns the companion consumer; `src/game/partyStore.ts` clears companion recovery timing on lethal damage, revive, and combat reset. Aura records are sampled at each pulse timestamp, so an aura expiring after a pulse still contributes to that pulse.
On the player path, source attack mode is approximated by the existing engaged-combat signal. For owned party NPCs, the source gate includes an active party target or a live engaged/threatened enemy, so the party's Stop command alone does not switch a companion to idle recovery. Native HP/Mana bypass shared HP5/Spirit, passive generic Mana, and the shared out-of-combat Mana floor. Other resource types continue through their existing resource model.
Focused validation is `npx vitest run src/game/romNativeRecovery.test.ts src/game/romNativeRecovery.integration.test.ts`; the parent task adds active-five NPC, secondary-Mana, and WoW-mode compatibility integration cases. Source and simulator limits remain: there is no sitting UI/state, no simulator equivalent for source `StopOntimeCure`, and player/party combat-mode detection is an approximation of source `IsAttackMode`. Native rates are source-derived; this audit does not certify sustained encounter pressure or change encounter budgets/readiness.
## Early level-one sustain diagnostic
The first native Knight level-one pull against Anglo ended after 141 seconds with the player and Rogue companion dead: Anglo's 2,772-HP pool was depleted, but incoming damage was 391.2, healing was 56, player damage was 118 across 6 casts, and 44 rotation decisions were resource-blocked. The pre-recovery/equipment baseline cleared the same pull in 54 seconds with 157.6 player HP remaining, 375 player damage across 19 casts, 262 healing, and 276 incoming damage. These two observations identified an additional attack-start and resource-rotation gap; they do not justify changing the source ReHP/ReMP formulas, and are not a full-cohort result.
Source Holy Strike `490148` is documented as a main-hand attack with Physical Light Damage. The imported direct hit was already level-one 16 holy damage, but its nonphysical damage school caused the generic attack-kind classifier to treat it as a spell; a cast therefore did not start the player's auto-attack. A separate `sourceAttackKind: "melee"` annotation now represents source delivery without changing effect school or amount. The focused regression confirms the cast remains 16 holy damage and is followed by a positive 22 physical auto-attack.
The level-one Priest observation showed max Mana 123 and ReMP 4.8, which gives an owned-NPC combat recovery pulse of 0.2 Mana every six seconds. At full party health its chooser selected 12-Mana Rising Tide despite having the 25-Mana Urgent Heal, confirming a finite-Mana rotation concern independent of recovery-rate math. A separate clean-room pre-level-10 healer policy reserves one learned direct heal before hostile Mana spending; it keeps source recovery unchanged. That reserve alone did not resolve the failed early encounter, so the native level-one boss training budget was separately reduced from 0.30 to 0.20. The unchanged final 80-pull cohort passes with zero player/NPC deaths and invalid casts. See [the aggregate verification and limits](ROM_NATIVE_RECOVERY_EQUIPMENT_PACING_PASS_2026-10-03.md).
@@ -0,0 +1,57 @@
# RoM Native Party Campaign Route Playtest — 2026-10-04
> **Current QA policy (2026-10-05):** Routine live tests use Stormwind Stockade: Cellblock Rush (`bite-sized-stormwind-stockade`); record the boss selected from the run ID. Full-source Stockade campaigns require explicit route selection. The Wailing captures and commands in this dated report remain historical; follow [the current test policy](TEST_DUNGEON_POLICY.md) and root `AGENTS.md`. A new Wailing reproduction needs an explicit owner request.
## Scope and build
Tested bounded entrance-to-encounter segments in Barren Caves and Wailing Caverns using the ordinary campaign picker. Each run used a UI-created level-30 RoM Priest / Knight healer and four active RoM NPC companions. Both dungeons entered in healer role with `gameMode=dungeon`, `gmTestMode=false`, and no Boss Testing state. Only initial profile level and secondary class were prepared for the isolated test profile. Dungeon entry, WASD movement, Tab targeting, party commands, ability keys, and ally selection used the game UI and normal inputs. Combat health, mana, damage, positions, cooldowns, enemy health, and targets were not changed by the harness.
The confirmed final production build used `index-CAMDJqEC.js`, `combatStore-t7bO4yKt.js`, `GameRuntime-otPnJCWI.js`, `PartyFrames-BsBsesPR.js`, and `index-499eecpe.css`.
## Roster Continue hit test
On the final build, the actual Continue button was clickable normally at both tested sizes. The 1440×900 layout and the 390×844 compact layout had no overlap with the floating toggle, and `elementFromPoint` at the button center hit Continue in each. The run recorded `forceClickUsed=false`.
- [Desktop Priest/Knight roster](../playtest-artifacts/native-routes/final-20261004-052623521/roster-priest-knight-level-30.png)
- [Compact Priest/Knight roster](../playtest-artifacts/native-routes/final-20261004-052623521/roster-compact-priest-knight-level-30.png)
- [Hit-test measurements and full run result](../playtest-artifacts/native-routes/final-20261004-052623521/results.json)
## Route results
| Campaign segment | Input and endpoint | Support and combat outcome |
| --- | --- | --- |
| Barren Caves, 90-second segment | 41 WASD movement steps; 68.13 m summed keyboard displacement and 69.34 m game distance; ended at “Uncharted Barren Caves.” | 15 effective player heals (6,154.63 total) and 7 effective player damage events (549 total); no party deaths. The level-30 profile naturally reached level 31. The endpoint view is partly blocked by a cave pillar, so this run demonstrates bounded movement and combat, not camera visibility or full navigation. |
| Wailing Caverns, fresh level-30 profile, 90-second segment | F1 Attack then F2 Defend; 15 WASD movement steps; 23.12 m summed keyboard displacement and 23.76 m game distance; ended at “The Winding Chasm - Entrance.” | 11 effective player heals (6,831.49 total), zero effective player damage events, and no party deaths. Three distinct entrance mob records were observed dead across snapshots: Deviate Guardian, Deviate Ravager, and Druid of the Fang. This does not claim a full route or total dungeon kill count. |
The Wailing run selected the longest-range bound hostile ability, Rising Tide (21.7 m), and used Urgent Heal (25 m). The first Wailing diagnostic had kept the party and healer too far apart and lost Rorik; that trace is preserved at `final-20261004-051737171` as a harness-policy diagnostic. The final run sampled live NPC positions, waited for healing casts to resolve, and issued F2 Defend after the initial F1 pull. Rorik survived this bounded segment, but the run produced no effective player damage, so it provides no player-DPS coverage.
The observed school list is from the combined combat event stream, including player and NPC activity; it does not establish that each enemy used every listed school. `killedMobNames` describes dead mobs still present in the endpoint snapshot. Wailing's three names above are the distinct dead records sampled during the segment, not a complete kill ledger.
## Evidence
**Barren Caves** — completed route record and screenshots:
- [Route JSON](../playtest-artifacts/native-routes/final-20261004-051413627/barren-caves-route.json)
- [Campaign picker](../playtest-artifacts/native-routes/final-20261004-051413627/barren-caves-campaign-picker.png)
- [Entrance](../playtest-artifacts/native-routes/final-20261004-051413627/barren-caves-entrance.png)
- [Keyboard traversal](../playtest-artifacts/native-routes/final-20261004-051413627/barren-caves-keyboard-traversal.png)
- [Encounter midpoint](../playtest-artifacts/native-routes/final-20261004-051413627/barren-caves-encounter-midpoint.png)
- [Segment endpoint](../playtest-artifacts/native-routes/final-20261004-051413627/barren-caves-segment-end.png)
The combined Barren/Wailing attempt has a follow-on `failure.json`: after Barren naturally advanced the profile to level 31, a harness assertion expected level 30 before starting the second route. The Barren route JSON and its screenshots are complete and are reported independently. Wailing was then run in a fresh level-30 profile.
**Wailing Caverns** — independent final route record and screenshots:
- [Run summary](../playtest-artifacts/native-routes/final-20261004-052623521/results.json)
- [Route JSON and detailed movement/heal records](../playtest-artifacts/native-routes/final-20261004-052623521/wailing-caverns-route.json)
- [Campaign picker](../playtest-artifacts/native-routes/final-20261004-052623521/wailing-caverns-campaign-picker.png)
- [Entrance](../playtest-artifacts/native-routes/final-20261004-052623521/wailing-caverns-entrance.png)
- [Keyboard traversal](../playtest-artifacts/native-routes/final-20261004-052623521/wailing-caverns-keyboard-traversal.png)
- [Encounter midpoint](../playtest-artifacts/native-routes/final-20261004-052623521/wailing-caverns-encounter-midpoint.png)
- [Segment endpoint](../playtest-artifacts/native-routes/final-20261004-052623521/wailing-caverns-segment-end.png)
Both route runs reported zero browser page exceptions. Each recorded one console-level 404 for the local `/favicon.ico` request. The Wailing run also records normal keyboard events, party positions, health and mana at entry and endpoint, cast outcomes, and sampled enemy deaths.
## Harness
The current `node scripts/playtest-native-routes.cjs --route-seconds=90` default runs an independent UI-created profile and one bounded **Stormwind Stockade: Cellblock Rush** segment; its boss is selected from the run ID and should be recorded. An explicitly requested full-source Stockade route uses `--route=stormwind-stockade`; Barren uses `--route=barren-caves`. Historical Wailing reproduction requires the owner's explicit request and `--historical-wailing --route=wailing-caverns`; it is not a default. The captures above used the older two-route harness. Run and review each authorized route independently to control its starting profile at level 30.
@@ -0,0 +1,67 @@
# RoM native stats source contract (2026-10-03)
This adapter is a source-derived RoM stat model for a selectable simulator ruleset. It keeps the existing shared `CharacterStats` contract available to combat code, but its `romNative` sidecar retains Runewaker semantics and raw point channels. It does not convert RoM hit, dodge, critical, or parry points to WoW ratings or percentages.
## Source records and identity
The stat exporter reads `racetable.db`, `sextable.db`, `voctable.db`, and `fixtable.db` from `F:\Projects\Runewaker\Resource\data`. Records begin at byte 140 and are 408 bytes. Vocation records contain two 408-byte records per class. The exporter validates the expected record IDs before interpreting floats and fails on non-finite values.
The player vocation argument rows are IDs 301003, 301005, 301007, 301009, 301011, 301013, 301015, 301017, 301019, and 301021 for Warrior through Champion. Playable race rows are 300000–300002 (Human, Elf, Dwarf); gender rows are 302000–302001 (male, female); the player formula/fix row is 303001. The generated output includes all ten classes, all three races, and both genders. The race and gender growth contributions are zero in these records, but their identities remain explicit inputs.
Formula definitions were checked against:
- `F:\Projects\Runewaker\SourceCodeVS2019\Libraries\Union\RoleData\RoleAttr.cpp`
- `F:\Projects\Runewaker\SourceCodeVS2019\Libraries\Union\RoleData\ObjectStruct.h`
- `F:\Projects\Runewaker\SourceCodeVS2019\Server\NetGameServer\MainProc\MagicProc\MagicProcess.cpp`
`romNativeStatRules.generated.json` records the source file hashes, row IDs, per-class/race/gender growth and coefficients, player FIX values, and formula notes. The generator also checks the Human/male base curves against `romBaseStatGrowth.generated.json`.
## Verified native formulas
At each level above 1, each base stat follows the table-defined progression `value = value * (1 + combinedPercentGrowth) + combinedFlatGrowth`. For a secondary vocation, Runewaker adds the secondary base at `Level_Sub` divided by ten. The helper accepts that secondary level; its primary-level fallback when the value is absent is simulator policy. The level-10 secondary-vocation unlock gate is also simulator policy, applied by the runtime caller rather than the source equation.
The source's MND attribute is exposed as Wisdom in the application. The player-derived channels implemented here are:
- Max HP: `(base HP + ExAddHP + STR*HpStrArg + STA*HpStaArg + flat MaxHP) * MaxHP_Rate`, minimum 1. The table adapter includes the base, attributes, flat gear, and rate; `ExAddHP` from external abilities/passives is outside this base helper.
- Max MP: `(base MP + INT*MPIntArg + MND*MpMndArg + flat MaxMP) * MaxMP_Rate`, minimum 0, when the primary or secondary class has the source MP resource type. The player `JobSpMpType` mapping gives MP to source classes 4–10 (Mage through Champion); classes 1–3 use SP. This does not replace current simulator Focus/Rage/Psi pools or change ability costs.
- ATK: `(STR*AtkStrArg + INT*AtkIntArg + AGI*AtkAgiArg + flat ATK) * ATK_Per`, minimum 1.
- DEF: `(STA*DefArg + flat DEF + armor-category base DEF contributions) * DEF_Per`, minimum 1. The helper calculates the attribute and flat-gear terms; its reference equipment curves do not contain source armor-category `BaseEQ.Def` values.
- MDEF: `(MND*MDefArg + flat MDEF) * MDEF_Rate`, minimum 1.
- MATK: `(INT*MAtkArg + flat MATK) * MATK_Rate`, minimum 1.
- DMG: `(ATK/DmgAtkArg when nonzero + flat DMG) * class/race/gender DmgRate * DMG_Per`, minimum 0. Player FIX row 303001 has `DmgAtkArg = 0`, so player gear DMG is flat.
- MDMG: `(MATK/MDmgMAtkArg when nonzero + flat MDMG) * MDMG_Per`, minimum 0. Player FIX row 303001 has `MDmgMAtkArg = 0`, so player gear MDMG is flat.
- MPow: the all-magic `BodyRate`, neutral 1. It is not MATK or MDMG.
The source's raw hit and avoidance channels are preserved as point values: physical hit adds `PhyHit_AgiArg * AGI`; physical dodge adds `PhyAvoid_AgiArg * AGI`; magical hit adds `MagHit_MndArg * MND`; magical dodge adds `MagAvoid_MndArg * MND + MagAvoid_AgiArg * AGI`. Physical/magic critical and parry are also source point channels. The sidecar does not label those values as percentages or ratings.
The verified Holy Heal inputs are source-backed, but the per-spell equation remains incomplete in this adapter. `MagicProcess.cpp` uses skill `OrgPower`, the capped `MND * 0.3 * SpellTime` contribution (cap branch gives `OrgPower * 6`), optional `MDMG * Dmg_HealArg`, then multiplies by `MPow * HealPowerRate` and adds `HealPoint * SpellTime`. Player FIX row 303001 supplies `Dmg_HealArg = 0.5`. The target-side modifier is `Power * (1 + HealAbsorbRate/100) + HealAbsorb` unless the effect is ignored. `romNative.healing` carries these coefficients and raw caster/target inputs; skill rank, `OrgPower`, timing, flags, random variance, undead behavior, and the full spell resolver remain outside this stat adapter.
## Equipment inputs and compatibility bridge
Native gear is an optional `ItemStats.romNative` payload. Its additive fields are explicitly source-semantic points; `*RateFactor` fields are multiplicative factors, with 1 neutral. `equipmentStats` combines flat values by addition and rate factors by multiplication. A source-native payload on an item takes precedence over the foreign-item bridge for that item, so mixed sets do not count its common direct values twice.
The native heirloom reader imports only `romNativeGearCurves.generated.json`, a compact five-class/slot/level table, and does not load the larger audit catalog at runtime. Those curves are source-selected Good-quality item references for Knight, Priest, Scout, Rogue, and Mage. The reference builder selects class/slot medians and selected package pieces, then applies its documented monotone level interpolation. This is simulator gear-profile policy, not a Runewaker per-level item formula. The remaining five classes and missing slots have no source-native curve.
The canonical converter keeps legacy reference aliases distinct: legacy `magicalDamage` is source type 148 MdmgPoint; legacy `magicalWeaponDamage` is type 191 MDMG; `weaponDamage` is type 25 DMG; `healingPower` is type 150 HealPoint; and `dodge` is type 17 physical dodge. The compact table therefore does not use a generic name normalizer that could map 148 into 191.
An audit of the 999 unique item IDs selected by the current five-class curves against the matching raw `armorobject.db`, `weaponobject.db`, and fixed `addpowerobject.db` records found no selected-item type 44 MPow, type 149 HealPowerRate, type 144 HealAbsorbRate, or type 147 HealAbsorb effects. Type 150 HealPoint occurs on two selected raw items and remains exported. The profile's neutral MPow/HealPowerRate factors therefore reflect absent effects on these selected references, not an assumed RoM conversion. The helper still accepts native payloads for those exact channels if a later source-specific item loader supplies them.
For items without a native payload, `romNativeGearFromSharedDirectStats` is an explicit compatibility simulator policy: it bridges only flat Strength, Stamina, Intellect, Agility, HP, and MP. WotLK Spirit is not Wisdom. WotLK ratings, Attack Power, Spell Power, armor, weapon DPS, and resistances are not interpreted as native RoM stats. Existing common item fields and their WotLK projections are preserved for compatibility.
At the shared combat boundary, runtime may use numeric native ATK as common attack power, MDMG as common spell power, and DEF as common armor under an explicit `combatStatModel` simulator label. That 1:1 adapter is for shared combat consumers; it does not assert equivalence to WoW stat definitions. MDEF and native point channels remain in the sidecar. A complete armor-defense calculation and verified native-point combat resolution are still open.
## Focused verification
`romNativeStats.test.ts` checks every class/race/gender primary curve, player-derived level-1 channels, MP gating, source healing coefficients, the 148/191 conversion boundary, a real level-70 Mage reference curve, rate-preserving aura recomputation, and gear aggregation. `equipment.test.ts` checks per-item payload precedence, foreign direct-stat bridging, mixed-loadout behavior, and native equip/unequip impact. `itemStats.test.ts` checks that native payload persistence does not change the existing WotLK numeric fields.
## Combat amount follow-up (2026-10-03)
The earlier per-spell boundary above is now partially bridged by `src/game/romNativeCombatAmount.ts`, `romNativeHealing.ts`, and `romNativeDamage.ts`. `romAbilityCatalog.ts` attaches a source skill/component key to supported native effect amounts; the runtime resolves that key against generated RuneWaker binding data. Direct HolyHeal calculation type 5 uses the source OrgPower/MagicLv and caster MND, MDMG, MPow, HealPowerRate, HealPoint inputs. The currently selected MagicLv is the character level clamped to 1–80, an explicit simulator policy rather than a source rank curve. This amount uses mean variance; the ordinary shared healing resolver continues to handle the common critical and overheal result.
The direct HolyHeal caster amount excludes target absorption fields; the source HealAbsorbRate and flat HealAbsorb are applied once for each actual recipient. DotMagic healing has its own source rank correction at application and stores its integer buff/tick amount for later pulses; player and NPC recipients reuse that same snapshot rather than reapplying the amount formula. It is not routed through the direct HolyHeal equation. The present all-magic MPow value does not establish missing element-specific BodyRate values. Unbound or unsupported components still use the shared simulator fallback.
The current direct-damage route accepts only supported active-five source components with a matching canonical training-weapon payload. `MagicAttackCalENUM` fixed types 0, 1, 2, 3, and 5–9 are implemented from the checked source enum; throw, prior-hit, and shield-category branches remain unsupported because the sidecar lacks their exact inputs. The consumer also declines `isShareDamage` components and components with nonzero `decreaseArg` on nonzero `rangeType` until exact runtime target-count and target-ordinal context is wired; the pure helper's support for these fields is not end-to-end area-damage support. Reflected Shot has a regression for this fail-closed boundary. Custom/unverified native equipment, missing source items/components, and unavailable school inputs keep the shared fallback. The returned ability amount stops at mean outgoing source power before source weapon variance, native hit/avoidance, and native target-defense handling; the existing shared target resolver remains the simulator bridge.
`nativeTrainingAutoAttackProfile` provides native physical weapon damage and intervals for player Knight main-hand attacks and NPC Knight/Rogue melee plus Scout Bow attacks; NPC Rogue offhand is also covered. Player Rogue offhand handling requires an explicitly present equipped inventory item. Player Scout Shot uses the native direct-damage route for its actual bound Shoot hit, not a continuous native bow-auto profile. Caster ambient basic-spell attacks keep the generic clock and MDMG policy. Player melee timing reads the existing common haste aura through `resolveAuraStatValue`, since native stat re-derivation does not populate the shared haste fields; the existing race-affix timing is retained. The final source-damage selection passed 13 tests: seven helper cases, two player/companion amount-parity and Reflected Shot fail-closed cases, and four actual auto/source-action cases. Native direct/periodic healing passed 14 player/NPC cases. These routes do not complete native hit/avoidance, armor categories, weapon variance, or critical resolution.
The final fixed player-rotation/native-companion diagnostic covers 80 pulls across the five requested builds at levels 1/10/30/60/65/66/79/80. All 80 targets died, with zero player/NPC deaths and zero invalid cast failures; trash took 4.5–9 seconds and Anglo 39–53.4 seconds. Native-only enemy health pacing is scoped separately from legacy WoW-stat RoM and other character origins; details and the exact bands are in [`ROM_NATIVE_COMBAT_PASS_2026-10-03.md`](ROM_NATIVE_COMBAT_PASS_2026-10-03.md). The ordinary randomized companion pool is now restricted to the active five identities; the configured factory remains broader for explicit party construction. Final production build passed with asset audits, compression, and bundle verification. Exact-dist browser QA passed with 11 screenshots captured and four representative roster, dungeon, NPC-stat, and mobile screenshots visually reviewed; current chunks were `index-D_h9IRuA.js` and `combatStore-BiA9BOQG.js`. There were no page, server, or HTTP errors and the network response-errors list was empty; the only console error was the optional existing favicon 404. A release check passed on 249 paths; the final documentation update requires the final hygiene/release check. The remaining limits are not a readiness promotion or complete balance certification.
@@ -0,0 +1,44 @@
# Targeted native RoM healing sustain audit — 2026-10-04
## Scope
This diagnostic runs three consecutive Barren Caves Anglo pulls at levels 60 and 80. Each pull uses the original RuneWaker NPC 101462 attack list and the existing boss health budget. The active five are the native RoM Knight player in the tank seat and owned Priest, Rogue, Scout, and Mage NPCs. The Priest is measured as the owned party actor `party-healer-0-rom-priest`; its healing events are selected by that exact `sourceActorId`, independently of player healing.
The test preserves party HP, Mana, effects, and cooldowns between pulls. The first interval has no enemy for 10 seconds; the second has no enemy for 90 seconds. It does not reset the party between encounters. The focused test writes its measurements to `artifacts/rom-enemy-followup/native-sustain-2026-10-04.json` when `ROM_NATIVE_SUSTAIN_REPORT=1`.
Heal-event `rawAmount` is reported separately because it can be affected by source modifiers. Event publication occurs synchronously inside the heal state update, so the test reads pre-heal actor HP in the event callback and derives post-heal HP from `effectiveAmount`. Delivered healing is the conserved `effectiveAmount + overheal`; the waste share below uses that delivered amount. Cast-time Mana cost is an estimate reconstructed from the actor's ability-cost calculation at release. Starting, minimum, and ending Mana are actual NPC resource-pool readings. The capacity shown in the table is the NPC's resource maximum captured at pull start; temporary effects may change capacity during a pull.
## Results
All six pulls cleared with the player and all four NPCs alive. The Priest never ran out of Mana. Pull time and boss damage vary by level and pull:
| Level | Pull | Clear | Boss damage to party | Priest minimum Mana / starting capacity | Minimum / starting capacity | Estimated Priest Mana cost |
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
| 60 | 1 | 79.1 s | 3,233 | 6,138 / 6,904 | 88.9% | 979 |
| 60 | 2 | 90.4 s | 7,344 | 5,711 / 8,077 | 70.7% | 911 |
| 60 | 3 | 80.6 s | 5,588 | 7,521 / 8,077 | 93.1% | 746 |
| 80 | 1 | 124.1 s | 47,618 | 17,286 / 17,924 | 96.4% | 1,255 |
| 80 | 2 | 123.3 s | 27,704 | 17,683 / 19,736 | 89.6% | 1,265 |
| 80 | 3 | 118.7 s | 24,385 | 19,123 / 19,736 | 96.9% | 1,178 |
Across level 60, the NPC Priest delivered 110,080 healing: 39,753 effective and 70,327 overheal (63.9%). At level 80 it delivered 264,241: 183,396 effective and 80,845 overheal (30.6%). The raw event-amount sums were 110,080 and 264,241 in these samples. The Priest released 15 `Heal` and 12 `Regenerate` casts at level 60, and 19 `Heal` and 13 `Regenerate` casts at level 80. Regenerate tick overheal accounts for 32,718 at level 60 and 51,936 at level 80; direct Heal packets account for 37,609 and 28,909 respectively. Periodic ticks after a paid cast do not each spend Mana.
Mana at the second pull shows what a short break restores without resetting actors. At level 60, the Priest had 6,154 Mana after pull 1 and 6,403 after 10 seconds; at level 80 it had 17,327 and 18,305. The 90-second breaks restored 2,366 at level 60 and 2,053 at level 80, taking the Priest to full of its pull-3 starting capacity.
The measured Priest remained at full health through all four breaks: 7,935/7,935 at level 60 and 29,286/29,286 at level 80. Cooldowns continued to run instead of being reset. For example, `rom-priest-general-3` had 50.9 seconds remaining before the level-60 short break and 40.9 afterward; at level 80, a 113.2-second cooldown became 23.2 seconds over the long break.
## Healing decision observation
The owned NPC attribution showed substantial overheal but not a safe direct-heal suppression rule. All observed Priest `Heal` cast starts had a pending `rom-priest-general-2` Regenerate, with the target's party/player health snapshot between 58% and 90%; the mirrored combat-actor HP is recorded separately to expose state differences. The casts take two seconds while Anglo continues attacking, and the lowest observed target snapshot was in that pressure window. Merely detecting a HoT would therefore suppress some direct heals during active damage. No full-health direct Heal appeared in the party/player health snapshot at cast start, and at least one direct heal remained observable with an active HoT at 60% health or below. The focused test guards both observations.
No healing AI or source recovery change was made. The audit records meaningful level-60 overheal and tests the emergency path, but it does not establish that changing the native source rates, direct-heal threshold, or HoT timing would improve survival across encounters. This remains a targeted sustain diagnostic, not a balance or readiness certification.
## Validation limits
The result covers one selected source boss, one active-five seating, and six deterministic local pulls. It does not establish campaign traversal, all RoM healer pairings, different boss attack mixes, mobile scene behavior, or class readiness. Run only the focused test for this diagnostic:
```powershell
$env:NODE_OPTIONS='--max-old-space-size=8192'
$env:ROM_NATIVE_SUSTAIN_REPORT='1'
npx vitest run src/game/romNativeSustain.integration.test.ts
```
@@ -0,0 +1,23 @@
# RoM Scout/Rogue player Auto Shot — 2026-10-04
## Source contract
The current Chronicles of Arcadia [Scout/Rogue skills list](https://chroniclesofarcadia.com/wiki/skills/list/2-3?locale=en) lists **Autoshot** under **Scout Primary Only**, source skill ID `492589`. It requires a ranged weapon, is instant and Physical, activates continuous shooting, deals 80.0% ranged weapon DPS per shot, and uses Physical Attack Speed for shot frequency. The row also says to use one piece of ammunition per shot. Its last-offensive-skill bonus is described only as “some portion”; the coefficient is not published and is not simulated. The source row does not specify a range value.
The local learned ability is `rom-scout-primary-57`. It is available to the verified Scout/Rogue build and retains the source primary-only identity, so Knight/Scout does not receive the skill. The ability bar uses the normal learned-ability catalog path. Its tooltip explains activation and reuse to stop the mode without presenting an unknown coefficient.
## Runtime behavior
The player’s Auto Shot state is `autoShotTargetId` plus `nextAutoShotAt`. Activation checks the living hostile target, owner, learned skill, and current resolved ranged slot. Scout Training Gear supplies a bow automatically, so an empty inventory and no explicit ranged assignment still have a valid weapon. A valid assigned ranged item overrides that baseline; unequipping it resolves back to the Training Gear bow. Activation itself does not deal damage or spend focus. Selecting another mob retargets an active mode without restarting its current timer; clearing the target, losing the target, death, or encounter reset clears the mode. Using Auto Shot again stops it even while another cast is active or target geometry blocks firing.
The source row does not state a numeric range, facing, line-of-sight, control, casting, or movement restriction. The runtime uses a six-unit interaction limit as a local constraint and the existing hostile cast geometry checks, which require facing and line of sight. Control that prevents actions and an active cast pause scheduled shots. A blocked shot does not charge Blood Arrow or advance its deadline. Auto Shot continues while moving because the source gives no movement restriction and the player runtime has no separate movement lock for this instant toggle.
For source-supported RoM training gear, damage and base cadence come from `nativeTrainingAutoAttackProfile` for the resolved ranged slot. The per-shot base is 80% of native ranged DPS (`source damage / source interval`), and cadence uses the native ranged interval followed by the represented `haste`, `ranged-haste`, and `attack-speed` modifiers and the current race-affix timing. If native training gear is unsupported or the resolved item is custom, the runtime falls back to that resolved item’s shared ranged DPS and speed. It never takes compatibility damage values as the native source profile.
Each committed shot is an ordinary ranged Physical combat event with ability ID `rom-scout-primary-57`. Active melee and off-hand Auto Attack timers are cleared and suppressed while Auto Shot is active; firing does not start parallel melee swings. Each committed attempt costs the verified Scout/Rogue Blood Arrow owner 2% of maximum health while the aura is active, with no additional mana. The cost is charged once before the damage roll and mirrored to player actor health when present; it is not contingent on landing a hit. The shot is skipped when paying would reduce the player to zero or less, and idle or blocked intervals cost nothing. No separate self-damage event is emitted for this cost.
The source’s ammunition use is not consumed by this runtime because there is no player ammunition inventory system. The unknown last-offensive-skill bonus is intentionally omitted rather than assigned an invented value.
## Verification
`src/game/romScoutAutoShot.integration.test.ts` covers source identity and learnability, automatic Training Gear with empty inventory, custom-item precedence and fallback after unequip, owner gating, native source damage and cadence distinct from compatibility budget, WoW compatibility fallback, custom native fallback with semantic haste, repeated scheduled shots, no activation hit or parallel melee/off-hand event, Blood Arrow cost and lethal-affordability skip, range/line-of-sight/facing/control/cast blocking without idle cost, unrestricted movement, target switching and clearing, reset, and same-tick death cleanup. The recurring test also verifies a stopped window without shots or HP drain, then reactivation with a fresh full-interval deadline and no immediate/catch-up hit. All thirteen checks pass.
+31
View File
@@ -0,0 +1,31 @@
# Current CoA Priest Holy Candle (490304)
## Source and precedence
- The [current CoA Priest skill list](https://chroniclesofarcadia.com/wiki/skills/list/5-1?locale=en) identifies Holy Candle as Priest-primary skill 490304 and gives a +27% healing-effectiveness bonus. Its displayed 5% HP trigger is stale.
- The same CoA row lists a 5% MP cost, range 1, and 30-second cooldown. The local row has no cost override, range 0.1, and a 180-second cooldown; the exact same-ID/name/class entry supports using CoA's metadata.
- The newer [CoA patch 12.1.6.2000 notes](https://chroniclesofarcadia.com/patch/12-1-6-2000) explicitly increase Holy Candle's self-damage from 5% to 12%, so the patch value takes precedence over the older page value.
- A [CoA developer reply on the Priest feedback thread](https://forum.chroniclesofarcadia.com/thread/4572-priest-class-feedback/?postID=30657) clarifies that Holy Candle can hit the caster only once per second.
- The skill page lists a 5% MP activation cost. This is distinct from the 12% HP self-damage trigger. The generated RuneWaker row has no cost, so the catalog supplies an ordinary 5% Mana cost, which resolves against maximum Mana; CoA does not specify a base-Mana cost.
## RuneWaker conflict and model
Generated local skill 490304 uses component 500549. It currently has range 0.1, a 180-second cooldown, no Mana cost, a 60-second duration, a type-149 +5% healing-done modifier, and a -6% HP periodic effect every second. The CoA behavior uses range 1, a 30-second cooldown, and a 5% Mana activation cost; replaces the +5% modifier with +27%; retains the local 60-second duration because CoA does not publish one; and removes the free-running periodic drain. The 5% Mana activation cost is separate from the HP trigger.
The patch says 12% self-damage but does not state whether the percentage uses current or maximum HP. The simulator interprets it as 12% of maximum HP, matching the local percentage-based component's existing maximum-health calculation pattern. This basis remains an implementation interpretation rather than an explicit CoA value.
The chosen trigger boundary is one charge for each accepted healing-spell cast that resolves a heal, independent of the number of recipients. Direct and AoE heal casts charge once before recipient fan-out, even when the recipients are already full. A HoT charges once when its valid application cast resolves; periodic healing ticks do not charge again. A channel charges on its first qualifying healing pulse, and a per-cast flag prevents later pulses from charging again even when they are more than one second apart. The official one-second throttle is exact and stored per owner: multiple heal spells from the same owner share a window, while the player and each companion have independent windows. Failed, invalid, or interrupted casts do not charge.
For the channel regression, the test uses WoW Divine Hymn only as a fixture for the shared channel scheduler while the simulated owner is a RoM Priest-primary character. This verifies the persistent per-cast guard; it does not claim Holy Candle or Divine Hymn has a CoA Priest-primary channel mapping. A test-only RoM Holy Candle HoT fixture covers application-versus-tick behavior because the generated Priest-primary catalog currently has no healing HoT row. The source leaves these timing boundaries unspecified, so they remain explicit simulator choices.
## Current implementation and limits
- `src/game/romPriestHolyCandleRuntime.ts` owns the current values, Priest-primary effect transform, aura marker, and pure throttle/self-damage helpers.
- `src/game/romAbilityCatalog.ts` gives only Priest-primary 490304 the 5% Mana cost, range 1, and 30-second cooldown plus a tagged 60-second +27% aura, replacing the generated periodic dot.
- `src/game/romPriestTooltips.ts` exposes the current values and separates cast cost from HP trigger cost.
- `src/game/romPriestHolyCandle.test.ts` covers catalog values, exact class scope, modifier replacement, periodic-dot removal, active-aura detection, and throttle math.
- `src/game/combatStore.ts` applies the player self-damage in the cast-resolution transaction and handles channel-pulse charging.
- `src/game/partyRuntime.ts` applies the same trigger for generated Priest-primary companions on direct/HoT heals and channel pulses; `src/game/partyStore.ts` retains the channel's charged flag across party-runtime advances.
- `src/game/romPriestHolyCandle.integration.test.ts` covers direct over-heal, one charge for multi-recipient Group Heal, inactive/invalid/interrupted casts, per-owner one-second throttling across spell IDs, companion heals, HoT application versus later ticks, and channel pulses more than one second apart.
The runtime hook applies raw self-damage up to the owner's remaining health and records it as a Holy damage event. The 12% basis remains maximum HP by simulator interpretation. The one-second timestamp map is per combat owner; the channel guard is per cast and persists on companion casts across scheduler updates. Integration coverage verifies the player and generated-companion paths described above.
Loaded 100 of 1528 files, more files were not shown because too many files have changed in this diff. Show more