← Back to Runs
Compare Runs
A (baseline)
B (current)
Avg Error A0.13%
Avg Error B0.11%
Δ Avg Error-0.02%
Changed20
Improved19
Regressed1
Added128
Retired1
Testcase Delta
542 / 542
Code / Config Changes
Commits (2b3f7928 → fde24e4d)
fde24e4dFIx testcase runner roundingpiddlyminx29/09/2026, 15:44:09
Code Changes (Run A → Run B)
Index: simulator/config/hero_definitions/Bradley.json===================================================================--- simulator/config/hero_definitions/Bradley.json prev run+++ simulator/config/hero_definitions/Bradley.json this run@@ -23,9 +23,11 @@},"PowerShot": {"description": "Bradley uses his expertise in suppressive artillery against the enemy vanguard, increasing Damage Dealt to Lancers by X% and to Infantry by Y% for all troops.","trigger": {- "type": "battle_start"+ "type": "engagement",+ "source": "any",+ "target": ["lancer", "infantry"]},"effects": {"PowerShot/1": {"type": "type.single_target.damage.up",@@ -35,12 +37,14 @@18,24,30],+ "engaged_with": ["lancer"],"units": {- "applies_vs": [- "lancer"- ]+ "applies_to": "trigger.source"+ },+ "duration": {+ "turns": { "count": 1 }}},"PowerShot/2": {"type": "type.single_target.damage.up",@@ -50,12 +54,14 @@15,20,25],+ "engaged_with": ["infantry"],"units": {- "applies_vs": [- "infantry"- ]+ "applies_to": "trigger.source"+ },+ "duration": {+ "turns": { "count": 1 }}}}},Index: simulator/config/hero_definitions/Gordon.json===================================================================--- simulator/config/hero_definitions/Gordon.json prev run+++ simulator/config/hero_definitions/Gordon.json this run@@ -5,30 +5,41 @@"skills": {"VenomInfusion": {"description": "Every 2 attacks, Lancers deal X% extra damage and apply poison to the target for 1 turn. Poisoned enemies deal Y% less damage.","trigger": {- "type": "attack",+ "type": "attack","every": 2,"source": "lancer"},"effects": {- "VenomInfusion/1": {- "type": "type.normal.damage.up",- "applies_to_damage_kinds": ["normal"],- "value": [- 20,- 40,- 60,- 80,- 100- ],+ "VenomInfusion/mark": {"units": {- "applies_to": "trigger.source",- "applies_vs": "trigger.target"+ "applies_to": "self.lancer",+ "applies_vs": "enemy.any"},"duration": {- "attacks": {- "count": 1+ "turns": { "count": 1 },+ "attacks": { "count": 1 }+ },+ "trigger_effects": {+ "VenomInfusion/1": {+ "type": "extra_skill_attack",+ "value": [20, 40, 60, 80, 100],+ "units": {+ "applies_to": "self.any",+ "applies_vs": "parent.use.target"+ },+ "trigger_damage_jobs": [+ {+ "source": "use.source",+ "target": "use.target",+ "damage_kind": "normal"+ }+ ],+ "duration": {+ "turns": { "delay": 1, "count": 1 },+ "attacks": { "count": 1 }+ }}}},"VenomInfusion/2": {@@ -60,9 +71,8 @@},"effects": {"ChemicalTerror/1": {"type": "active.hero.damage.up",- "applies_to_damage_kinds": ["normal"],"value": [30,60,90,@@ -75,10 +85,9 @@]},"duration": {"turns": {- "count": 1,- "delay": 1+ "count": 1}},"same_effect_stacking": "max"},@@ -100,30 +109,8 @@"count": 1}},"same_effect_stacking": "max"- },- "ChemicalTerror/3": {- "type": "active.hero.damage.up",- "applies_to_damage_kinds": ["skill"],- "value": [- 30,- 60,- 90,- 120,- 150- ],- "units": {- "applies_to": [- "lancer"- ]- },- "duration": {- "turns": {- "count": 1- }- },- "same_effect_stacking": "max"}}},"ToxicRelease": {Index: simulator/config/hero_definitions/README.md===================================================================--- simulator/config/hero_definitions/README.md prev run+++ simulator/config/hero_definitions/README.md this run@@ -134,11 +134,12 @@| --- | --- || `pre_battle` | Activated once while preparing the battle, before any runtime exists. Chance-free by definition and restricted to static `passive.*` effects; these feed the static damage profile (in-game: widget passives baked into player bonus stats). || `battle_start` | Is attempted once during battle setup, before round 1. `first`, `every`, `source`, and `target` do not gate this trigger type. || `turn` | Is attempted once at the start of matching simulator rounds. Turn triggers must not define `source` or `target`; scope their effects instead. |+| `engagement` | Is attempted at turn start, after `turn` skills and before turn-created carriers are used, once for each living `source` unit whose chosen target this turn (including attack-order effects such as Ambusher) matches `target`. Effects may use `trigger.source`/`trigger.target`. Troop class advantages use it: a line engaged with its favored class is empowered for everything it deals that turn, including splash on other units. Bradley's Power Shot also uses it; a direct effect may add `engaged_with` (see Effects) to activate only for particular engaged classes. || `attack` | Is attempted procedurally for a matching **normal** attack, after locked-target exhaustion and pre-existing `no_attack` checks. Generated skill jobs do not evaluate it. |-Only these three exact strings are scheduled by the runtime. An unknown string is not rejected by a closed trigger schema; it simply leaves the skill unscheduled.+Only these exact strings are scheduled by the runtime. An unknown string is not rejected by a closed trigger schema; it simply leaves the skill unscheduled.Each attack is one procedural cluster. Effects produced by an earlier attack can affect later attacks, but a later intent cannot retroactively change an earlier attack. Target order is applied while locking that attack's target, before its trigger stage.### `trigger.probability`@@ -194,10 +195,12 @@For an `attack` trigger, `source` and `target` are matched directly against each intended normal attack. Reina demonstrates the reverse-side form: `source: "enemy.any"` and `target: "self.any"` listens for an enemy attack against Reina's side.`turn` triggers reject `source` and `target`. They have no attack-shaped source or target; use concrete effect scopes. A broad turn-scoped effect can participate in every matching normal attack during its active window. For example, an `extra_skill_attack` applying to `self.any` with `turns.count: 1` can emit one extra job for each eligible troop attack that turn without matching the generated skill jobs.-Ahmose's Viper Formation creates a one-turn Infantry `no_attack` effect on each scheduled turn, even without Infantry. Only using that effect to pause an attack creates its two `trigger_effects` for damage reduction. Those children start next turn and last two complete turns; an unused pause expires without granting protection. The configuration's `reason` records why activation and actual use are separate.+Turn-triggered extra attacks run during self-applied `no_attack` pauses, but enemy-applied `no_attack` controls suppress them. Both prevent attack triggers, attack-triggered follow-ups, and normal cadence advancement. Ahmose/Wayne captures verify the self-pause behavior; Sonya/Hendrik and Sonya/Wayne captures verify stun suppression. Other control/skill combinations remain predictions unless separately verified.+Ahmose's Viper Formation counts four actual Infantry attacks, then schedules an Infantry pause for the following turn and damage reduction for that turn and the next. Without Infantry attacks it earns neither pause nor protection.+`pre_battle` and `battle_start` never have an attack-shaped intent. Its `source` and `target` fields are compiled but never used for matching; use effect scopes, not trigger selectors, to scope a battle-start effect.## Effects@@ -214,8 +217,9 @@| `applies_to_damage_kinds` | Non-empty array containing `normal` and/or `skill` | Optional runtime-modifier applicability gate. Omitted means both kinds. Restricts eligible damage jobs without changing the bucket selected by `type`. || `units` | `{ applies_to?, applies_vs? }` | Resolves which troop lines may receive/use the effect and which opposing troop lines it applies against. || `duration` | `{ turns?, attacks? }` | Optional round window and/or use limit. Omitted means permanent, except that extra-attack effects default to one turn and one attack. || `same_effect_stacking` | `add` or `max` | Controls overlap between live activations of the same modifier definition and scope. Omitted means `add`. |+| `engaged_with` | Non-empty array of `infantry`, `lancer`, `marksman` | `engagement` skills only, on direct effects: activate this effect only for a line whose target this turn is one of these units. Lets one skill give a different bonus per engaged class (Power Shot). || `requires_effect` | Effect ID string | Applies a runtime damage modifier only while the named effect is applicable to the same damage job. || `value_evolution` | Evolution object | Optionally changes the effect value as rounds or uses advance. || `trigger_damage_jobs` | Non-empty array of job definitions | Required for `extra_skill_attack`; describes the damage jobs it emits. || `trigger_effects` | Object keyed by child effect ID | Defines children materialized only from an actual parent use. |@@ -313,9 +317,9 @@`applies_vs: "all"` is deliberately rejected; use `"any"`. `units.side` is also rejected. Side belongs in relation-qualified selectors such as `enemy.any`.`trigger.source`/`trigger` resolve to an attack trigger's dealer side and unit. `trigger.target`/`target` resolve to its locked taker side and unit. Direct turn effects and pre-battle/battle-start effects reject attack-relative selectors. A nested effect instead uses `parent.use.source` and `parent.use.target`; these resolve from the concrete job or control in which the typed parent actually participated.-An effect can define both its normal `type` and keyed `trigger_effects`. Its children activate only when the parent is actually used. A type-less effect is a normal-attack carrier: when its unit scopes match an eligible normal attack, it materializes its keyed children and consumes a use. The carrier is useful for bounded one-use consequences without inventing a combat bucket. Children are snapshotted after the parent's use, so a child cannot recursively affect the same consuming damage job.+An effect can define both its normal `type` and keyed `trigger_effects`. Its children activate only when the parent is actually used. A type-less effect is a normal-attack carrier: when its unit scopes match an eligible normal attack, it materializes its keyed children and consumes a use. A carrier created by a `turn` trigger is instead used at the start of that turn, before any attack, by the first living unit in its `applies_to` scope against that unit's current target. A unit under an enemy `no_attack` control cannot use it, and an unused turn carrier is discarded. The carrier is useful for bounded one-use consequences without inventing a combat bucket. Children are snapshotted after the parent's use, so a child cannot recursively affect the same consuming damage job.The parser also accepts `"friendly"`, but only as “all units on this field's default side.” It is not an owner-relative synonym in every context. No current hero definition uses it; use `self.any`, `enemy.any`, or `any` instead.## Duration@@ -347,9 +351,9 @@For example, an attack-triggered effect created during round 3 with `{ "turns": { "delay": 1, "count": 2 } }` is active in rounds 4 and 5 and expires at the start of round 6.An attack-triggered effect with `{ "turns": { "count": 1 } }` is available for later jobs in the same round, but expires before the next round begins. It does not mean “the next full turn.”-The native troop skills MasterBrawler, Charge, and RangedStrike use source/target matchup conditions on their attack triggers, apply their buffs to `trigger.source`, and use `{ "turns": { "count": 1 } }`. They omit effect-level `applies_vs`: the matchup controls activation, not subsequent recipients. The buff applies to the triggering attack and later attacks by that troop type in the same round, including extra attacks against other troop types. Extra attacks do not activate these skills again.+The native troop skills MasterBrawler, Charge, and RangedStrike, and Bradley's Power Shot, use `engagement` triggers with a source/target matchup, apply their buffs to `trigger.source`, and use `{ "turns": { "count": 1 } }`. They omit effect-level `applies_vs`: the matchup controls activation, not subsequent recipients. The buff applies to every hit that troop type deals that round, including extra attacks against other troop types.**Battle-start delay gotcha.** Battle-start effects are created at setup round 0, while the earliest active round is clamped to 1. Consequently, both `turns.delay: 0` and `turns.delay: 1` start in round 1. A battle-start effect needs `delay: 2` to begin in round 2. No current hero definition combines `battle_start` with a turn delay, but the distinction matters when authoring one.### `attacks`@@ -458,14 +462,16 @@Target-specific modifiers are selected against each generated job's actual recipient. They do not inherit the initiating normal attack's target or its matchup bonuses.The extra-attack effect is charged once for the parent normal attack if at least one of its jobs runs. If its `value` is non-positive, every job lacks living source/target troops, or every job is skipped because its target is already exhausted, the effect is not charged and can remain available.-Immediate and delayed hits share bucket evaluation, shield settlement, and target caps. Immediate hits calculate and consume their modifiers together. Delayed hits instead separate captured contributions from attack-limited target modifiers.+Immediate and delayed hits are the same calculation. When an `extra_skill_attack` with a turn delay is materialized as a carrier's `trigger_effects` child, each of its jobs is calculated in full at that moment, with two exceptions. Shields are ignored: the kills land at the next turn start, before that turn's shields activate, so shields never absorb or get consumed by a delayed hit. Next-hit modifiers (attack-limited target-side modifiers such as Gwen's Eagle Vision) depend on what used the carrier. A turn-start carrier (Renee's Dream Mark) is its own damage event, so it takes and consumes the live ones. Extra damage attached to an attack (Gordon's Venom Infusion) is part of that attack: it gets exactly the next-hit modifiers the attack's normal hit applied and consumes nothing further. Only the resulting kills are deferred. They are applied at the start of the turn the child would activate, capped by that turn's troop snapshot and the round's per-target cap. Attacks in that turn are still declared against the snapshot, so a target the delayed hit wiped out is still attacked, for zero kills. The child itself never joins the live extra-attack index.-When an `extra_skill_attack` is materialized as a carrier's `trigger_effects` child, its generated damage is retained on that child ActiveEffect. All modes retain owned dynamic factors and captured static terms so delivery can combine modifiers without recalculating the source's troop strength. Attack-limited target modifiers and shields are not selected, advanced, or consumed during capture. When a later normal attack matches the child's source and target scope, pending damage lands before that attack is declared and before it creates new effects. Delivery applies the currently eligible attack-limited target modifiers to the captured buckets, consumes their uses, and settles live shields and the current target-troop cap. If no matching attack occurs during the child's duration, the pending damage expires without consuming those modifiers or shields.+Turn start runs in this order: delayed hits land; the previous turn's effects expire and this turn's scheduled effects activate, except shields; `turn` skills fire; `engagement` skills fire; turn-created carriers are used; scheduled shields activate.Renee's Nightmare Trace uses this form with a one-turn delay: the even-round Lancer attack locks the target and calculates the damage, then a matching allied attack on the following odd round delivers it. Its child uses `self.any` for delivery eligibility; the retained job still uses the original Lancer source and locked target, allowing delivery after the Lancers die. The precise capture ordering and treatment of defensive state remain provisional reverse-engineering assumptions.+Pending captured hits land before the matching normal attack's control check, even if that attack will be stunned or paused. New mark placement still requires an unblocked Lancer attack. Pure-Lancer Renee/Sonya captures verify both boundaries: a turn-6 stun prevents placement, while a mark placed on turn 10 still lands during the turn-11 stun. This does not make fresh scheduled strikes stun-immune.+Renee's Dreamslice mark increases both normal and skill damage taken by the marked target. Dreamcatcher's Lancer-specific increase remains restricted to normal damage.All jobs emitted by one use read the parent extra-attack effect's same current `value`; its use/evolution is charged only after those jobs finish. Other attack-limited **modifier** effects are different: each generated skill job is a separate modifier use, and modifiers are charged after each job, so a one-job modifier can expire before the second target in the same extra attack is calculated.@@ -486,13 +492,13 @@- `applies_vs` is the would-be target;- chance belongs on the skill's `trigger.probability` when needed; it decides whether the control effect is created;- `value` is ignored.-Attack-triggered controls are activated during the all-triggers phase and can cancel the same normal intent that triggered them. All matching attack skills have already attempted before the cancellation is applied.+Pre-existing `no_attack` controls are checked before attack triggers. An attack-triggered control cannot cancel the normal attack that created it; it applies on a later eligible attack.-If both a no-attack and dodge control apply to the same normal attack, no-attack wins. If several live controls of the same type match, the last one encountered is reported as the winning control; matching attack-limited controls can still be charged together. `same_effect_stacking` does not select among controls.+If both a no-attack and dodge control apply to the same normal attack, no-attack wins. If several live controls of the same type match, the last one encountered is reported as the winning control; matching attack-limited controls can still be charged together. Any matching enemy-applied `no_attack` suppresses turn-triggered extras, even if a self-pause is the last reported control. `same_effect_stacking` does not select among controls.-Controls are checked from the live index for each attack in procedural order. A one-use broad control expires after its first actual use and cannot be pre-attached to later attacks. `no_attack` emits no normal or extra job and advances no cadence counter. Dodge emits a zero-kill normal outcome with `dodged: true`, advances normal cadence, and allows attack triggers and extra jobs to continue.+Controls are checked from the live index for each attack in procedural order. A one-use broad control expires after its first actual use and cannot be pre-attached to later attacks. `no_attack` emits no normal job and advances no cadence counter. Fresh turn-triggered extra jobs run only if every applicable `no_attack` is owned by the attacking side; attack-triggered follow-ups and new mark placement do not run. Previously captured hits land before the control check. Dodge emits a zero-kill normal outcome with `dodged: true`, advances normal cadence, and allows attack triggers and extra jobs to continue.### `attack_order`Overrides target preference for matching normal attacks. Although no current hero definition uses it, it is a supported native effect type.@@ -519,11 +525,12 @@| --- | --- || `hero_generation` | `SR`, `S1`, `S1_natalia`, `S1_jeronimo`, `S2` through `S10` || `troop_type` | `infantry`, `lancer`, `marksman` || `requirements[].type/value` | `engagement_type` with `rally` or `garrison`, always beginning at level 1 |-| `trigger.type` | `pre_battle`, `battle_start`, `turn`, `attack` |-| `trigger.source` | attack triggers only: omitted, `infantry`, `lancer`, `marksman`, `self.any`, `self.all`, `enemy.any` |-| `trigger.target` | attack triggers only: omitted or `self.any` |+| `trigger.type` | `pre_battle`, `battle_start`, `turn`, `engagement`, `attack` |+| `trigger.source` | attack/engagement triggers only: omitted, `infantry`, `lancer`, `marksman`, `any`, `self.any`, `self.all`, `enemy.any` |+| `trigger.target` | attack/engagement triggers only: omitted, `self.any`, or `["lancer", "infantry"]` |+| `engaged_with` | only Bradley's Power Shot: `["lancer"]`, `["infantry"]` || `trigger.probability` | omitted or a five-level numeric percentage array || `trigger.first` | omitted, 4, or 5 || `trigger.every` | omitted, 2, 3, 4, 5, or 6 || `units.applies_to` | omitted; unit strings/arrays; `all`; relation-qualified selectors; attack-relative selectors; nested `parent.use.*` selectors |Index: simulator/config/troop_skills.json===================================================================--- simulator/config/troop_skills.json prev run+++ simulator/config/troop_skills.json this run@@ -11,9 +11,9 @@"value": 0}],"trigger": {- "type": "attack",+ "type": "engagement","source": "infantry","target": "lancer"},"effects": {@@ -162,9 +162,9 @@"value": 0}],"trigger": {- "type": "attack",+ "type": "engagement","source": "lancer","target": "marksman"},"effects": {@@ -320,9 +320,9 @@"value": 0}],"trigger": {- "type": "attack",+ "type": "engagement","source": "marksman","target": "infantry"},"effects": {Index: simulator/src/config.test.ts===================================================================--- simulator/src/config.test.ts prev run+++ simulator/src/config.test.ts this run@@ -320,8 +320,24 @@assert.throws(() => loadSimulatorConfigFromDir(removedDelay), /unknown trigger_damage_jobs key delivery_delay_turns/i);assert.throws(() => loadSimulatorConfigFromDir(removedExtraKind), /damage_kind.*normal.*skill/i);});+test("engaged_with is accepted only on engagement skill effects with valid units", () => {+ const effect = (engagedWith: unknown) => ({+ type: "type.single_target.damage.up",+ value: 10,+ engaged_with: engagedWith,+ units: { applies_to: "trigger.source" },+ duration: { turns: { count: 1 } }+ });+ const engagement = { type: "engagement", source: "any", target: ["lancer", "infantry"] };+ assert.doesNotThrow(() => loadSimulatorConfigFromDir(writeConfigWithTroopEffect(effect(["lancer"]), engagement)));+ assert.throws(() => loadSimulatorConfigFromDir(writeConfigWithTroopEffect(effect(["lancer"]))), /engaged_with.*engagement/i);+ for (const invalid of [[], ["cavalry"], "lancer"]) {+ assert.throws(() => loadSimulatorConfigFromDir(writeConfigWithTroopEffect(effect(invalid), engagement)), /engaged_with must be/i);+ }+});+test("loadSimulatorConfig accepts modifier damage-kind applicability and rejects invalid uses", () => {const valid = writeConfigWithTroopEffect({type: "active.hero.damageTaken.up",applies_to_damage_kinds: ["normal"],Index: simulator/src/config.ts===================================================================--- simulator/src/config.ts prev run+++ simulator/src/config.ts this run@@ -113,8 +113,9 @@validateNativeEffectUnits(effect as EffectIntentDefinition, file, skillId, effectId);validateNativeEffectValue(effect as EffectIntentDefinition, file, skillId, effectId);validateAppliesToDamageKinds(effect as EffectIntentDefinition, file, skillId, effectId);validateRequiredEffect(effect as EffectIntentDefinition, effectDefinitions, file, skillId, effectId);+ validateEngagedWith(skill.trigger, effect as EffectIntentDefinition, nested, file, skillId, effectId);validateEffectValueFormula(skill.trigger, effect as EffectIntentDefinition, file, skillId, effectId);if (type === "attack_order") validateAttackOrderEffect(effect as EffectIntentDefinition, file, skillId, effectId);validateNativeEffectDuration(effect as EffectIntentDefinition, file, skillId, effectId);validateStaticBucketEffect(skill.trigger, effect as EffectIntentDefinition, file, skillId, effectId);@@ -190,8 +191,27 @@if (effect.trigger_effects) yield* walkEffectDefinitionsWithDepth(effect.trigger_effects, true);}}+function validateEngagedWith(+ trigger: SkillFile["skills"][string]["trigger"],+ effect: EffectIntentDefinition,+ nested: boolean,+ file: string,+ skillId: string,+ effectId: string+): void {+ if (effect.engaged_with === undefined) return;+ const path = `${file}:${skillId}.${effectId}.engaged_with`;+ if (trigger.type !== "engagement" || nested) {+ throw new Error(`engaged_with is only supported on direct effects of engagement skills at ${path}`);+ }+ const units = effect.engaged_with as unknown;+ if (!Array.isArray(units) || units.length === 0 || !units.every((unit) => unit === "infantry" || unit === "lancer" || unit === "marksman")) {+ throw new Error(`engaged_with must be a non-empty list of infantry, lancer or marksman at ${path}`);+ }+}+function validateRequiredEffect(effect: EffectIntentDefinition,effectDefinitions: Map<string, EffectIntentDefinition[]>,file: string,Index: simulator/src/damage.test.ts===================================================================--- simulator/src/damage.test.ts prev run+++ simulator/src/damage.test.ts this run@@ -3,9 +3,8 @@import {generateDamageJob,deliverDamageJob,- retainGeneratedDamage,type DamageJobOptions,ceilIgnoringFloatResidue,createDamageScratch,evaluateDamageExpression@@ -106,11 +105,8 @@if (!group) {group = {ordinal: groups.length,bucketIndex: DYNAMIC_BUCKETS.findIndex((definition) => definition.name === activeEffect.intent.type),- attackLimitedTakerModifier: activeEffect.kind === "modifier" &&- activeEffect.duration.attacks !== undefined &&- DYNAMIC_BUCKETS.find(definition => definition.name === activeEffect.intent.type)?.jobSide === "taker",sameEffectStacking: activeEffect.sameEffectStacking};byResolvedGroup.set(key, group);groups.push(group);@@ -148,10 +144,11 @@test("float-safe ceilings ignore residue but preserve genuine fractional troops", () => {assert.equal(ceilIgnoringFloatResidue(200.00000000000003), 200);assert.equal(ceilIgnoringFloatResidue(Math.sqrt(2) * Math.sqrt(2)), 2);- assert.equal(ceilIgnoringFloatResidue(10 + 5e-13), 10);- assert.equal(ceilIgnoringFloatResidue(10 + 2e-12), 11);+ assert.equal(ceilIgnoringFloatResidue(10 + 5e-11), 10);+ assert.equal(ceilIgnoringFloatResidue(10 + 2e-10), 11);+ assert.equal(ceilIgnoringFloatResidue(200000 - 99999.99999999999), 100000);assert.equal(ceilIgnoringFloatResidue(200.001), 201);assert.equal(ceilIgnoringFloatResidue(0.01), 1);});@@ -490,91 +487,8 @@assert.ok(Math.abs(damageTakenUp.kills - baseline.kills * 1.25) < 1e-12);assert.ok(Math.abs(damageTakenDown.kills - baseline.kills / 1.25) < 1e-12);});-test("retained damage preserves generation modifiers and health conversion across scratch reuse", () => {- for (const mode of ["fast", "trace"] as const) {- const fighters = simpleFighters();- const health = effect("active.hero.health.up", "defender", 100);- const shield: ActiveEffect = {- ...effect("active.hero.shield", "defender", 8),- kind: "shield",- duration: { turns: { count: 2 } },- intent: {- id: "source-shield",- type: "active.hero.shield",- value: 8,- value_formula: { type: "percent_of", source: "trigger.source_attack" }- }- };- const index = preparedEffectIndex([health, shield]);- indexEffect(index, health);- const options = damageJobOptions(fighters, [], {- effectIndex: index,- scratch: createDamageScratch(),- recorder: createRecorder(mode, [], () => { throw new Error("damage-only recorder"); })- });- const expected = calculateIndexedDamageJob(job, fighters, [effect("active.hero.health.up", "defender", 100)]);- const retained = retainGeneratedDamage(generateDamageJob(job, fighters, options));- expireEffectIndex(index, health);- const interveningJob = { ...job, sourceMultiplier: 3 };- const intervening = deliverDamageJob(interveningJob, generateDamageJob(interveningJob, fighters, options), options);- assert.ok(intervening.kills > expected.kills);- indexEffect(index, shield);- const delivered = deliverDamageJob({ ...job, round: 2 }, retained, options);- assert.ok(Math.abs(delivered.kills - Math.max(0, expected.kills - 4)) < 1e-12, mode);- if (mode === "trace") {- assert.equal(delivered.trace?.atomicBuckets["active.hero.health.up"].totalPct, 100);- assert.equal(delivered.trace?.damageBeforeOffsets, expected.kills);- assert.equal(delivered.trace?.offsetDamage, 4);- }- }-});--test("damage generation leaves shield delay and protection untouched until delivery", () => {- const fighters = simpleFighters();- const shield: ActiveEffect = {- ...effect("active.hero.shield", "defender", 4),- kind: "shield",- duration: { turns: { count: 2 } },- remainingAttackDelay: 1- };- const options = damageJobOptions(fighters, [shield], { trace: true, scratch: createDamageScratch() });- const baseline = calculateIndexedDamageJob(job, fighters, []).kills;- const first = retainGeneratedDamage(generateDamageJob(job, fighters, options));- const second = retainGeneratedDamage(generateDamageJob(job, fighters, options));- const firstArrival = deliverDamageJob(job, first, options);- const secondArrival = deliverDamageJob(job, second, options);- assert.equal(firstArrival.kills, baseline);- assert.equal(secondArrival.kills, Math.max(0, baseline - 4));- assert.equal(firstArrival.trace?.offsetDamage, 0);- assert.equal(secondArrival.trace?.offsetDamage, 4);-});--test("delayed damage ignores shields that expire or deplete before arrival", () => {- const fighters = simpleFighters();- const expired: ActiveEffect = {- ...effect("active.hero.shield", "defender", 100),- kind: "shield",- duration: { turns: { count: 1 } }- };- const depleted: ActiveEffect = {- ...effect("active.hero.shield", "defender", 3),- kind: "shield",- duration: { turns: { count: 2 } }- };- const options = damageJobOptions(fighters, [expired, depleted], { trace: true, scratch: createDamageScratch() });- const baseline = calculateIndexedDamageJob(job, fighters, []).kills;- const retained = retainGeneratedDamage(generateDamageJob(job, fighters, options));- expireEffectIndex(options.effectIndex, expired);- const preceding = deliverDamageJob(job, generateDamageJob(job, fighters, options), options);- assert.equal(preceding.kills, Math.max(0, baseline - 3));- const arrival = deliverDamageJob({ ...job, round: 2 }, retained, options);- assert.equal(arrival.kills, baseline);- assert.equal(arrival.trace?.offsetDamage, 0);- assert.equal(arrival.appliedEffects?.some((applied) => "kind" in applied && applied.kind === "shield"), false);-});-test("additive turn shields conserve same-group and independent budgets across successive hits", () => {const fighters = simpleFighters();const baseline = calculateIndexedDamageJob(job, fighters, []).kills;const first: ActiveEffect = {Index: simulator/src/damage.ts===================================================================--- simulator/src/damage.ts prev run+++ simulator/src/damage.ts this run@@ -89,9 +89,9 @@const DYNAMIC_NEUTRAL_VALUES = Float64Array.from(DYNAMIC_BUCKETS.map(({ update }) => bucketNeutralValue(update)));const STATIC_NEUTRAL_VALUES = Float64Array.from(STATIC_BUCKETS.map(({ update }) => bucketNeutralValue(update)));const DAMAGE_SCALE_BUCKET = createEvaluatedDamageBucket(1 / 100);// Smallest tested power-of-ten tolerance that removes the verified residue.-const CEILING_EPSILON = 1e-12;+const CEILING_EPSILON = 1e-10;/** Smaller side's initial army; battle-invariant. */export function minInitialArmy(fighters: Record<SideId, ResolvedFighter>): number {return Math.max(@@ -112,19 +112,31 @@usedEffects?: ActiveEffect[];/** Effects whose primary mechanic actually won/applied; excludes duration-only siblings. */primaryUsedEffects?: ActiveEffect[];minInitialArmy?: number;+ /**+ * Next-hit modifiers this job takes over from the attack it is part of, in place of the live+ * next-hit groups: it neither reads nor consumes those (an attack-attached delayed hit).+ */+ inheritedNextHit?: readonly NextHitModifier[];+ /** Shields neither absorb nor are consumed by this job (delayed hits land before shields go up). */+ ignoreShields?: boolean;}-/** Immediate generation borrows scratch; captured generation owns its factors and static terms. */+/** One next-hit modifier value as a damage job applied it. */+export interface NextHitModifier {+ effect: ActiveEffect;+ bucketIndex: number;+ value: number;+}++/** Borrowed from scratch: deliver it before generating the next job. */export interface GeneratedDamage {factors?: Float64Array;recording: DamageJobRecorder;armyTerm: number;damageBeforeOffsets: number;healthFactor: number;- capturedDealerFactor?: number;- capturedTakerFactor?: number;}export function generateDamageJob(job: DamageJob,@@ -150,90 +162,24 @@buckets.factors[DYNAMIC_BUCKET_INDEX["active.troop.health.down"]];return generated;}-export function retainGeneratedDamage(generated: GeneratedDamage): GeneratedDamage {- return {- factors: generated.recording.needsFactors ? generated.factors!.slice() : undefined,- recording: generated.recording,- armyTerm: generated.armyTerm,- damageBeforeOffsets: generated.damageBeforeOffsets,- healthFactor: generated.healthFactor- };-}--/** Snapshot source/static/turn-based contributions; attack-limited taker modifiers wait for landing. */-export function generateCapturedDamageJob(- job: DamageJob,- fighters: Record<SideId, ResolvedFighter>,- options: DamageJobOptions-): GeneratedDamage {- const recording = options.recorder.startDamageJob();- const buckets = options.scratch ? resetDamageScratch(options.scratch) : createNumericDamageBuckets();- const usedEffects = options.usedEffects ?? [];- const armyTerm = populateSourceBuckets(job, fighters, options, buckets);- applyPartitionedBucketEffects(job, options.effectIndex, buckets, recording, usedEffects, options.primaryUsedEffects ?? usedEffects, false);- const capturedDealerFactor = bucketSetValue(options.staticDamageProfile[job.dealerSide][job.dealerUnit].dealerFactor);- const capturedTakerFactor = bucketSetValue(options.staticDamageProfile[job.takerSide][job.takerUnit].takerFactor);- const expression = DYNAMIC_EXPRESSIONS[job.kind];- const damageBeforeOffsets = multiplySlots(1, buckets.factors, expression.numeratorSlots) /- multiplySlots(1, buckets.factors, expression.denominatorSlots) *- capturedDealerFactor * capturedTakerFactor * bucketSetValue(DAMAGE_SCALE_BUCKET);- return {- factors: options.scratch ? buckets.factors.slice() : buckets.factors,- recording,- armyTerm,- damageBeforeOffsets,- healthFactor: dynamicHealthFactor(buckets.factors),- capturedDealerFactor,- capturedTakerFactor- };-}--/** Add current taker attack budgets to the original buckets, then settle current shields and caps. */-export function deliverCapturedDamageJob(- job: DamageJob,- generated: GeneratedDamage,- options: DamageJobOptions-): DamageResult {- const buckets = options.scratch ? resetDamageScratch(options.scratch) : createNumericDamageBuckets();- buckets.factors.set(generated.factors!);- const usedEffects = options.usedEffects ?? [];- applyPartitionedBucketEffects(job, options.effectIndex, buckets, generated.recording, usedEffects, options.primaryUsedEffects ?? usedEffects, true);- const expression = DYNAMIC_EXPRESSIONS[job.kind];- // Re-evaluate, rather than dividing by captured factors: a captured bucket may be zero.- const damageBeforeOffsets = multiplySlots(1, buckets.factors, expression.numeratorSlots) /- multiplySlots(1, buckets.factors, expression.denominatorSlots) *- generated.capturedDealerFactor! * generated.capturedTakerFactor! * bucketSetValue(DAMAGE_SCALE_BUCKET);- return finishDamageJob(job, generated, options, buckets, damageBeforeOffsets, dynamicHealthFactor(buckets.factors));-}-export function deliverDamageJob(job: DamageJob,generated: GeneratedDamage,options: DamageJobOptions): DamageResult {- const { damageBeforeOffsets, healthFactor } = generated;+ const { recording, armyTerm, damageBeforeOffsets, healthFactor } = generated;const buckets = options.scratch ?? createNumericDamageBuckets();if (generated.factors !== buckets.factors) {resetDamageScratch(buckets);if (generated.factors) buckets.factors.set(generated.factors);}- return finishDamageJob(job, generated, options, buckets, damageBeforeOffsets, healthFactor);-}--function finishDamageJob(- job: DamageJob,- generated: GeneratedDamage,- options: DamageJobOptions,- buckets: NumericDamageBuckets,- damageBeforeOffsets: number,- healthFactor: number-): DamageResult {- const { recording, armyTerm } = generated;const usedEffects = options.usedEffects ?? [];const primaryUsedEffects = options.primaryUsedEffects ?? usedEffects;- const offsetDamage = applyShields(job, options.effectIndex, buckets, recording, damageBeforeOffsets, healthFactor, usedEffects, primaryUsedEffects);+ const offsetDamage = options.ignoreShields+ ? 0+ : applyShields(job, options.effectIndex, buckets, recording, damageBeforeOffsets, healthFactor, usedEffects, primaryUsedEffects);const rawDamage = Math.max(0, damageBeforeOffsets - offsetDamage);const takerTroops = job.roundStartTroops[job.takerSide][job.takerUnit] ?? 0;const kills = options.capToTakerTroops === false ? rawDamage : Math.min(takerTroops, rawDamage);return recording.finish({ job, factors: buckets.factors, armyTerm, damageBeforeOffsets, offsetDamage, rawDamage, kills });@@ -247,63 +193,59 @@recording: DamageJobRecorder,usedEffects: ActiveEffect[],primaryUsedEffects: ActiveEffect[]): number {- const armyTerm = populateSourceBuckets(job, fighters, options, buckets);+ // Fractional casualties carry between rounds, but every positive remainder is+ // still one living troop and contributes fully to the next attack.+ const dealerTroops = ceilIgnoringFloatResidue(+ Math.max(0, job.roundStartTroops[job.dealerSide][job.dealerUnit] ?? 0)+ );+ const initialArmy = options.minInitialArmy ?? minInitialArmy(fighters);+ const armyTerm = Math.sqrt(dealerTroops) * Math.sqrt(initialArmy);+ applyDynamicDamageBucketValue(buckets, "troops.count", armyTerm);+ applyDynamicDamageBucketValue(buckets, "source.multiplier", job.sourceMultiplier ?? 1);const jobSlot = damageJobSlot(job);+ const groups = options.effectIndex.damageGroupsByJobShape[jobSlot];+ const inherited = options.inheritedNextHit;applyBucketEffects(- options.effectIndex.damageGroupsByJobShape[jobSlot],+ inherited ? groups.filter((group) => !group.nextHit) : groups,options.effectIndex.liveEffectsByGroup,job.round,jobSlot,buckets,recording,usedEffects,primaryUsedEffects);+ if (inherited) {+ for (const { effect, bucketIndex, value } of inherited) {+ applyBucketValue(buckets.factors, bucketIndex, value, BUCKET_UPDATE_BY_INDEX);+ recording.recordEffect(effect, value);+ }+ }return armyTerm;}-function populateSourceBuckets(- job: DamageJob,- fighters: Record<SideId, ResolvedFighter>,- options: DamageJobOptions,- buckets: NumericDamageBuckets-): number {- // Fractional casualties carry between rounds, but every positive remainder is- // still one living troop and contributes fully to the next attack.- const dealerTroops = ceilIgnoringFloatResidue(- Math.max(0, job.roundStartTroops[job.dealerSide][job.dealerUnit] ?? 0)- );- const initialArmy = options.minInitialArmy ?? minInitialArmy(fighters);- const armyTerm = Math.sqrt(dealerTroops) * Math.sqrt(initialArmy);- applyDynamicDamageBucketValue(buckets, "troops.count", armyTerm);- applyDynamicDamageBucketValue(buckets, "source.multiplier", job.sourceMultiplier ?? 1);- return armyTerm;-}--function dynamicHealthFactor(factors: Float64Array): number {- return factors[DYNAMIC_BUCKET_INDEX["active.hero.health.up"]] *- factors[DYNAMIC_BUCKET_INDEX["active.troop.health.up"]] /- factors[DYNAMIC_BUCKET_INDEX["active.hero.health.down"]] /- factors[DYNAMIC_BUCKET_INDEX["active.troop.health.down"]];-}--function applyPartitionedBucketEffects(- job: DamageJob,- index: EffectIndex,- buckets: NumericDamageBuckets,- recording: DamageJobRecorder,- usedEffects: ActiveEffect[],- primaryUsedEffects: ActiveEffect[],- attackLimitedTakerModifier: boolean-): void {- const jobSlot = damageJobSlot(job);- for (const group of index.damageGroupsByJobShape[jobSlot]) {- if (group.attackLimitedTakerModifier !== attackLimitedTakerModifier) continue;- applyEffectGroup(group, index.liveEffectsByGroup, job.round, jobSlot, buckets, recording, usedEffects, primaryUsedEffects, attackLimitedTakerModifier);+/**+ * The next-hit modifier values a job applied, reconstructed from the effects it used: a+ * max-stacking group contributes its largest value, an additive group every value.+ */+export function appliedNextHitModifiers(usedEffects: readonly ActiveEffect[], round: number): NextHitModifier[] {+ const applied: NextHitModifier[] = [];+ const maxByGroup = new Map<ActiveEffectGroup, NextHitModifier>();+ for (const effect of usedEffects) {+ const group = effect.effectGroup;+ if (!group?.nextHit) continue;+ const modifier = { effect, bucketIndex: group.bucketIndex, value: effect.getCurrentValue(round) };+ if (group.sameEffectStacking !== "max") {+ applied.push(modifier);+ continue;+ }+ const previous = maxByGroup.get(group);+ if (!previous || modifier.value > previous.value) maxByGroup.set(group, modifier);}+ return [...applied, ...maxByGroup.values()];}function applyBucketEffects(@@ -328,13 +270,12 @@jobSlot: number,buckets: NumericDamageBuckets,recording: DamageJobRecorder,usedEffects: ActiveEffect[],- primaryUsedEffects: ActiveEffect[],- attackLimitedTakerModifier?: boolean+ primaryUsedEffects: ActiveEffect[]): void {const dependency = group.requiredGroupOrdinalsByJobShape;- if (dependency && !requiredEffectIsApplicable(dependency, liveEffectsByGroup, round, jobSlot, attackLimitedTakerModifier)) return;+ if (dependency && !requiredEffectIsApplicable(dependency, liveEffectsByGroup, round, jobSlot)) return;const effects = liveEffectsByGroup[group.ordinal];if (effects.length === 0) return;if (group.sameEffectStacking !== "max") {for (const effect of effects) {@@ -416,17 +357,14 @@function requiredEffectIsApplicable(dependency: Array<number[] | undefined>,liveEffectsByGroup: ActiveEffect[][],round: number,- jobSlot: number,- attackLimitedTakerModifier?: boolean+ jobSlot: number): boolean {const requiredOrdinals = dependency[jobSlot];if (!requiredOrdinals) return false;for (const ordinal of requiredOrdinals) {for (const effect of liveEffectsByGroup[ordinal]) {- if (attackLimitedTakerModifier !== undefined &&- effect.effectGroup!.attackLimitedTakerModifier !== attackLimitedTakerModifier) continue;if (isEffectAttackReady(effect) && effect.getCurrentValue(round) !== 0) return true;}}return false;Index: simulator/src/effectIndex.test.ts===================================================================--- simulator/src/effectIndex.test.ts prev run+++ simulator/src/effectIndex.test.ts this run@@ -121,9 +121,8 @@if (!group) {group = {ordinal: groups.length,bucketIndex: 0,- attackLimitedTakerModifier: false,sameEffectStacking: effect.sameEffectStacking};byResolvedGroup.set(key, group);groups.push(group);Index: simulator/src/extraAttacks.ts===================================================================--- simulator/src/extraAttacks.ts prev run+++ simulator/src/extraAttacks.ts this run@@ -11,34 +11,34 @@import { advanceEffectAttackDelay } from "./effects";import {generateDamageJob,deliverDamageJob,- generateCapturedDamageJob,- deliverCapturedDamageJob,ceilIgnoringFloatResidue,- type DamageJobOptions+ type DamageJobOptions,+ type NextHitModifier} from "./damage";import { normalizeUnitType } from "./normalize";+import type { BattleRecorder } from "./recorder";import {capJobToRemainingTarget,chargeEffectUse,chargeUsedEffectsForJob,effectUseIntent,+ expireActiveEffect,materializeTriggeredEffects,targetExhausted,type DamageJobResult,type RunLoopOptions,type Runtime} from "./runtime";-// Pending jobs land before the matching normal attack is declared; immediate jobs-// run after its damage. Each effect participates in only one phase, so its attack-// delay advances once per matching normal attack. Only immediate skill kills feed-// that normal attack's deferred formulas.-// The effect is charged one use only when at least one of its own jobs actually ran.-// Snapshot eligible effects before delivery because charging may expire them.+// Immediate jobs run after the normal attack's damage. A self-paused normal attack still+// permits turn-triggered jobs, but not attack-triggered follow-ups. Only immediate skill+// kills feed deferred formulas. The effect is charged one use only when at least one of+// its own jobs actually ran. Snapshot eligible effects before delivery because charging+// may expire them.export function processExtraAttacks(- phase: "pending" | "immediate",+ phase: "immediate" | "cancelled",normalAttack: DamageJob,intent: AttackIntent,runtime: Runtime,fighters: Record<SideId, ResolvedFighter>,@@ -54,92 +54,53 @@let skillKills = 0;// Snapshot the applicable effects: charging an effect below may expire it out of the live index.const effects = runtime.effectIndex.extraAttacks.filter((effect) =>- (phase === "pending" ? (effect.pendingDamageJobs?.length ?? 0) > 0 : effect.pendingDamageJobs === undefined) &&+ (phase !== "cancelled" || effect.sourceSkill?.trigger.type === "turn") &&extraAttackEffectAppliesToNormalAttack(effect, normalAttack) &&advanceEffectAttackDelay(effect));for (const effect of effects) {const sourceEffectId = effect.source.effectId ?? effect.intent.id;let processedJobCount = 0;let firstProcessedJob: DamageJob | undefined;- if (effect.pendingDamageJobs) {- const pendingJobs = effect.pendingDamageJobs;- let retainedJobCount = 0;- for (const pending of pendingJobs) {- const deliveryJob: DamageJob = {- ...pending.job,- round,- calculationRound: pending.job.round,- roundStartTroops- };- if (loopOptions.capRoundKills && targetExhausted(deliveryJob, roundStartTroops, roundTargetDamage)) {- pendingJobs[retainedJobCount++] = pending;- continue;- }- recorder.recordScheduledDamageJob(deliveryJob);- const result = deliverCapturedDamageJob(deliveryJob, pending.generated, damageJobOptions);- if (deliveryJob.kind === "skill") recorder.recordSkillDamageJob(deliveryJob, effect);- if (loopOptions.capRoundKills) {- capJobToRemainingTarget(result, deliveryJob, roundStartTroops, roundTargetDamage, recorder);- } else if (loopOptions.capJobKills) {- result.kills = Math.min(- result.kills,- Math.max(0, roundStartTroops[deliveryJob.takerSide][deliveryJob.takerUnit] ?? 0)- );- recorder.recordFinalKills(result);- }- results.push({ job: deliveryJob, result, intent });- totalKills += result.kills;- if (deliveryJob.kind === "skill") {- skillKills += result.kills;- runtime.extraSkillAttackJobsByEffect[sourceEffectId] = (runtime.extraSkillAttackJobsByEffect[sourceEffectId] ?? 0) + 1;- }- processedJobCount += 1;- firstProcessedJob ??= deliveryJob;- chargeUsedEffectsForJob(runtime, deliveryJob, recorder);- }- pendingJobs.length = retainedJobCount;- } else {- for (const definition of effect.triggerDamageJobs ?? []) {- const sources = resolveTriggerJobSelector(definition.source, "source", effect, normalAttack, roundStartTroops);- const targets = resolveTriggerJobSelector(definition.target, "target", effect, normalAttack, roundStartTroops);- const multiplier = effect.getCurrentValue(round) / 100;- if (multiplier <= 0) continue;- for (const source of sources) {- if (ceilIgnoringFloatResidue(roundStartTroops[source.side][source.unit] ?? 0) <= 0) continue;- for (const target of targets) {- if (ceilIgnoringFloatResidue(roundStartTroops[target.side][target.unit] ?? 0) <= 0) continue;- const job: DamageJob = {- round,- kind: definition.damage_kind ?? "skill",- roundStartTroops,- dealerSide: source.side,- dealerUnit: source.unit,- takerSide: target.side,- takerUnit: target.unit,- sourceEffectId,- sourceMultiplier: multiplier- };- if (loopOptions.capRoundKills && targetExhausted(job, roundStartTroops, roundTargetDamage)) continue;- recorder.recordScheduledDamageJob(job);- const generated = generateDamageJob(job, fighters, damageJobOptions);- const result = deliverDamageJob(job, generated, damageJobOptions);- if (job.kind === "skill") recorder.recordSkillDamageJob(job, effect);- if (loopOptions.capRoundKills) {- capJobToRemainingTarget(result, job, roundStartTroops, roundTargetDamage, recorder);- }- results.push({ job, result, intent });- totalKills += result.kills;- if (job.kind === "skill") {- skillKills += result.kills;- runtime.extraSkillAttackJobsByEffect[sourceEffectId] = (runtime.extraSkillAttackJobsByEffect[sourceEffectId] ?? 0) + 1;- }- processedJobCount += 1;- firstProcessedJob ??= job;- chargeUsedEffectsForJob(runtime, job, recorder);+ for (const definition of effect.triggerDamageJobs ?? []) {+ const sources = resolveTriggerJobSelector(definition.source, "source", effect, normalAttack, roundStartTroops);+ const targets = resolveTriggerJobSelector(definition.target, "target", effect, normalAttack, roundStartTroops);+ const multiplier = effect.getCurrentValue(round) / 100;+ if (multiplier <= 0) continue;+ for (const source of sources) {+ if (ceilIgnoringFloatResidue(roundStartTroops[source.side][source.unit] ?? 0) <= 0) continue;+ for (const target of targets) {+ if (ceilIgnoringFloatResidue(roundStartTroops[target.side][target.unit] ?? 0) <= 0) continue;+ const job: DamageJob = {+ round,+ kind: definition.damage_kind ?? "skill",+ roundStartTroops,+ dealerSide: source.side,+ dealerUnit: source.unit,+ takerSide: target.side,+ takerUnit: target.unit,+ sourceEffectId,+ sourceMultiplier: multiplier+ };+ if (loopOptions.capRoundKills && targetExhausted(job, roundStartTroops, roundTargetDamage)) continue;+ recorder.recordScheduledDamageJob(job);+ const generated = generateDamageJob(job, fighters, damageJobOptions);+ const result = deliverDamageJob(job, generated, damageJobOptions);+ if (job.kind === "skill") recorder.recordSkillDamageJob(job, effect);+ if (loopOptions.capRoundKills) {+ capJobToRemainingTarget(result, job, roundStartTroops, roundTargetDamage, recorder);}+ results.push({ job, result, intent });+ totalKills += result.kills;+ if (job.kind === "skill") {+ skillKills += result.kills;+ runtime.extraSkillAttackJobsByEffect[sourceEffectId] = (runtime.extraSkillAttackJobsByEffect[sourceEffectId] ?? 0) + 1;+ }+ processedJobCount += 1;+ firstProcessedJob ??= job;+ chargeUsedEffectsForJob(runtime, job, recorder);}}}if (processedJobCount > 0) {@@ -150,24 +111,38 @@}return { totalKills, skillKills };}-export function captureTriggeredExtraDamage(+// A delayed extra attack (a carrier child with a turn delay) is calculated in full when its+// parent is used; only its kills are deferred, landing at the start of the turn the child+// would activate. Landing precedes that turn's shields, so shields never touch it.+// Next-hit modifiers depend on what the parent use was:+// - a turn-start event (Renee's Dream Mark) is its own damage event, so it takes and consumes+// the live next-hit modifiers (inheritedNextHit omitted);+// - extra damage attached to an attack (Gordon's Venom Infusion) is part of that attack: it+// gets exactly the next-hit modifiers the attack's normal hit applied, consuming nothing more.+export function calculateDelayedDamage(effects: ActiveEffect[],- normalAttack: DamageJob,+ parentUse: DamageJob,fighters: Record<SideId, ResolvedFighter>,damageJobOptions: DamageJobOptions,- runtime: Runtime+ runtime: Runtime,+ inheritedNextHit?: readonly NextHitModifier[]): void {- const { round, roundStartTroops } = normalAttack;+ const { round, roundStartTroops } = parentUse;+ const settleOptions: DamageJobOptions = {+ ...damageJobOptions,+ capToTakerTroops: false,+ ignoreShields: true,+ ...(inheritedNextHit ? { inheritedNextHit } : {})+ };for (const effect of effects) {- if (effect.expired || effect.intent.type !== "extra_skill_attack" || effect.pendingDamageJobs) continue;+ if (effect.expired || effect.intent.type !== "extra_skill_attack") continue;+ const landingRound = Math.max(effect.startRound, round + 1);const multiplier = effect.getCurrentValue(round) / 100;- if (multiplier <= 0) continue;- const pending = [];- for (const definition of effect.triggerDamageJobs ?? []) {- const sources = resolveTriggerJobSelector(definition.source, "source", effect, normalAttack, roundStartTroops);- const targets = resolveTriggerJobSelector(definition.target, "target", effect, normalAttack, roundStartTroops);+ for (const definition of multiplier > 0 ? effect.triggerDamageJobs ?? [] : []) {+ const sources = resolveTriggerJobSelector(definition.source, "source", effect, parentUse, roundStartTroops);+ const targets = resolveTriggerJobSelector(definition.target, "target", effect, parentUse, roundStartTroops);for (const source of sources) {if (ceilIgnoringFloatResidue(roundStartTroops[source.side][source.unit] ?? 0) <= 0) continue;for (const target of targets) {if (ceilIgnoringFloatResidue(roundStartTroops[target.side][target.unit] ?? 0) <= 0) continue;@@ -181,18 +156,55 @@takerUnit: target.unit,sourceEffectId: effect.source.effectId ?? effect.intent.id,sourceMultiplier: multiplier};- const generated = generateCapturedDamageJob(job, fighters, damageJobOptions);- pending.push({ job, generated });+ const result = deliverDamageJob(job, generateDamageJob(job, fighters, settleOptions), settleOptions);chargeUsedEffectsForJob(runtime, job, damageJobOptions.recorder);+ const landing = runtime.delayedDamageByRound[landingRound];+ const pending = { job, result, effect };+ if (landing) landing.push(pending);+ else runtime.delayedDamageByRound[landingRound] = [pending];}}}- if (pending.length > 0) effect.pendingDamageJobs = pending;+ // The child has done its work; it never joins the live extra-attack index.+ expireActiveEffect(runtime, effect);}}+/** Apply kills of delayed hits due this turn, capped by the turn's troop snapshot and round cap. */+export function landDelayedDamage(+ round: number,+ runtime: Runtime,+ roundStartTroops: DamageJob["roundStartTroops"],+ roundTargetDamage: Record<SideId, Record<UnitType, number>>,+ loopOptions: RunLoopOptions,+ recorder: BattleRecorder,+ results: DamageJobResult[]+): void {+ const landing = runtime.delayedDamageByRound[round];+ if (!landing) return;+ runtime.delayedDamageByRound[round] = undefined;+ for (const { job, result: settled, effect } of landing) {+ const deliveryJob: DamageJob = { ...job, round, calculationRound: job.round, roundStartTroops };+ if (targetExhausted(deliveryJob, roundStartTroops, roundTargetDamage)) continue;+ recorder.recordScheduledDamageJob(deliveryJob);+ const result = { ...settled };+ if (loopOptions.capRoundKills) {+ capJobToRemainingTarget(result, deliveryJob, roundStartTroops, roundTargetDamage, recorder);+ } else if (loopOptions.capJobKills) {+ result.kills = Math.min(result.kills, Math.max(0, roundStartTroops[deliveryJob.takerSide][deliveryJob.takerUnit] ?? 0));+ recorder.recordFinalKills(result);+ }+ if (deliveryJob.kind === "skill") {+ recorder.recordSkillDamageJob(deliveryJob, effect);+ const sourceEffectId = effect.source.effectId ?? effect.intent.id;+ runtime.extraSkillAttackJobsByEffect[sourceEffectId] = (runtime.extraSkillAttackJobsByEffect[sourceEffectId] ?? 0) + 1;+ }+ results.push({ job: deliveryJob, result, intent: effectUseIntent(deliveryJob) });+ }+}+function extraAttackEffectAppliesToNormalAttack(effect: ActiveEffect, normalAttack: DamageJob): boolean {return (effect.appliesTo.side === normalAttack.dealerSide &&unitMaskHas(effect.appliesTo.units, normalAttack.dealerUnit) &&Index: simulator/src/runtime.ts===================================================================--- simulator/src/runtime.ts prev run+++ simulator/src/runtime.ts this run@@ -27,8 +27,10 @@// Live troop counts, initialized from the fighters' immutable initialTroops.troops: Record<SideId, Record<UnitType, number>>;activateEffectsByRound: Array<ActiveEffect[] | undefined>;expireEffectsByRound: Array<ActiveEffect[] | undefined>;+ // Delayed hits already settled in full, keyed by the round whose start applies their kills.+ delayedDamageByRound: Array<DelayedDamage[] | undefined>;// Per-job scratch: effects that affected the job being calculated; drained by// chargeUsedEffects (uses += 1 each) after every job in every mode.usedEffects: ActiveEffect[];primaryUsedEffects: ActiveEffect[];@@ -54,8 +56,14 @@takerSide: SideId;};}+export interface DelayedDamage {+ job: DamageJob;+ result: DamageResult;+ effect: ActiveEffect;+}+export interface DamageJobResult {job: DamageJob;result: DamageResult;intent?: AttackIntent;@@ -72,8 +80,9 @@skills.damageGroupsByJobShape),activateEffectsByRound: [],expireEffectsByRound: [],+ delayedDamageByRound: [],usedEffects: [],primaryUsedEffects: [],staticDamageProfile,damageScratch: createDamageScratch(),@@ -112,23 +121,38 @@if (effects) effects.push(effect);else schedule[round] = [effect];}+// Shields scheduled for this turn are held back for activateScheduledShields, which runs+// after turn-trigger skills: a turn-start event (Renee's Dream Mark) never meets a shield+// scheduled by the previous turn's attacks.export function processEffectSchedule(runtime: Runtime, round: number): void {const expiring = runtime.expireEffectsByRound[round];if (expiring) {for (const effect of expiring) expireActiveEffect(runtime, effect);runtime.expireEffectsByRound[round] = undefined;}const activating = runtime.activateEffectsByRound[round];if (activating) {+ const shields: ActiveEffect[] = [];for (const effect of activating) {- if (!effect.expired) indexEffect(runtime.effectIndex, effect);+ if (effect.expired) continue;+ if (effect.kind === "shield") shields.push(effect);+ else indexEffect(runtime.effectIndex, effect);}- runtime.activateEffectsByRound[round] = undefined;+ runtime.activateEffectsByRound[round] = shields.length > 0 ? shields : undefined;}}+export function activateScheduledShields(runtime: Runtime, round: number): void {+ const shields = runtime.activateEffectsByRound[round];+ if (!shields) return;+ for (const effect of shields) {+ if (!effect.expired) indexEffect(runtime.effectIndex, effect);+ }+ runtime.activateEffectsByRound[round] = undefined;+}+export function triggerSkills(triggerType: "battle_start" | "round_start" | "attack_declared",round: number,skills: ResolvedSkill[],@@ -235,12 +259,14 @@export function targetExhausted(job: DamageJob,roundStartTroops: DamageJob["roundStartTroops"],- roundTargetDamage: Record<SideId, Record<UnitType, number>>+ roundTargetDamage: Record<SideId, Record<UnitType, number>>,+ ignoredTargetDamage?: Record<SideId, Record<UnitType, number>>): boolean {const available = Math.max(0, roundStartTroops[job.takerSide][job.takerUnit] ?? 0);- return ceilIgnoringFloatResidue(Math.max(0, available - roundTargetDamage[job.takerSide][job.takerUnit])) === 0;+ const damaged = roundTargetDamage[job.takerSide][job.takerUnit] - (ignoredTargetDamage?.[job.takerSide][job.takerUnit] ?? 0);+ return ceilIgnoringFloatResidue(Math.max(0, available - damaged)) === 0;}export function capJobToRemainingTarget(result: DamageResult,Index: simulator/src/runtimeSkills.ts===================================================================--- simulator/src/runtimeSkills.ts prev run+++ simulator/src/runtimeSkills.ts this run@@ -22,8 +22,9 @@// Chance-free static-passive skills activated once at prepare time, before any runtime exists.preBattle: ResolvedSkill[];battleStart: ResolvedSkill[];roundStart: PreparedRoundSkill[];+ engagement: PreparedEngagementSkill[];attackDeclaredByJobShape: Array<PreparedAttackSkill[] | undefined>;effectGroups: ActiveEffectGroup[];damageGroupsByJobShape: ActiveEffectGroup[][];randomness: BattleRandomness;@@ -42,8 +43,13 @@everyAttack?: number;firstAttack?: number;}+export interface PreparedEngagementSkill {+ skill: ResolvedSkill;+ probabilityPct: number;+}+export interface PreparedRoundSkill {skill: ResolvedSkill;probabilityPct: number;everyTurn?: number;@@ -54,8 +60,9 @@const all = fighters.flatMap((fighter) => [...(fighter.heroSkills ?? []), ...fighter.troopSkills]);const preBattle: ResolvedSkill[] = [];const battleStart: ResolvedSkill[] = [];const roundStart: PreparedRoundSkill[] = [];+ const engagement: PreparedEngagementSkill[] = [];const attackDeclaredByJobShape: Array<PreparedAttackSkill[] | undefined> = Array.from({ length: DAMAGE_JOB_SHAPE_SLOTS });const chanceSkillIds: Record<SideId, string[]> = { attacker: [], defender: [] };const effectGroups: ActiveEffectGroup[] = [];const damageGroupsByJobShape: ActiveEffectGroup[][] = Array.from({ length: DAMAGE_JOB_SHAPE_SLOTS }, () => []);@@ -89,8 +96,10 @@everyTurn: skill.trigger.every,firstTurn: skill.trigger.first ?? skill.trigger.every})});+ } else if (skill.trigger.type === "engagement") {+ engagement.push({ skill, probabilityPct: trigger.probabilityPct });} else if (skill.trigger.type === "attack") {const immediateEffects: ResolvedEffectIntentDefinition[] = [];const deferredIntents = skill.effects.filter((intent) => intent.value_formula !== undefined);for (const intent of skill.effects) {@@ -142,10 +151,9 @@const group: ActiveEffectGroup = {ordinal: effectGroups.length,bucketIndex: damageBucketIndex(definition.name),sameEffectStacking: effect.sameEffectStacking,- attackLimitedTakerModifier: effect.kind === "modifier" &&- effect.duration.attacks !== undefined && definition.jobSide === "taker"+ nextHit: effect.kind === "modifier" && effect.duration.attacks !== undefined && definition.jobSide === "taker"};groupMetadata.set(group, {ownerSide: skill.side,effectId: intent.id,@@ -175,8 +183,9 @@return {preBattle,battleStart,roundStart,+ engagement,attackDeclaredByJobShape,effectGroups,damageGroupsByJobShape,randomness: {Index: simulator/src/simulator.test.ts===================================================================--- simulator/src/simulator.test.ts prev run+++ simulator/src/simulator.test.ts this run@@ -20,26 +20,66 @@function runOnce(input: BattleInput, config: SimulatorConfig, options: SimulationOptions = {}) {return runPrepared(prepareBattle(input, config), undefined, options);}-test("Gordon suppresses on third turns and boosts normal Lancer damage on the following turns", () => {- const result = runOnce({- maxRounds: 7,- attacker: {- troops: { lancer_t6: 1000 },- heroes: { Gordon: { skill_1: 2, skill_2: 2, skill_3: 2 } }- },- defender: { troops: { lancer_t6: 1000 } }- }, loadSimulatorConfig(), { mode: "standard" });+test("Gordon's captured Venom damage matches the Ahmose and Wu Ming interaction", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/ahmose_gordon_renee/ahmose_gordon_vs_wuming.json", import.meta.url), "utf8"));+ const result = runOnce(input, loadSimulatorConfig());+ assert.equal(signedRemainingScore(result), 140);+ for (const [skillId, activations] of [+ ["ViperFormation", 5],+ ["VenomInfusion", 34],+ ["ChemicalTerror", 22],+ ["ToxicRelease", 17]+ ] as const) {+ assert.equal(result.skillReport.attacker.find(skill => skill.skillId === skillId)?.skillActivations, activations, skillId);+ }+});- assert.deepEqual(result.attacks- .filter((attack) => attack.appliedEffects?.some((effect) => effect.effectId === "ChemicalTerror/1"))- .map((attack) => attack.round), [4, 7]);- assert.deepEqual(result.attacks- .filter((attack) => attack.appliedEffects?.some((effect) => effect.effectId === "ChemicalTerror/2"))- .map((attack) => attack.round), [3, 6]);+test("Gordon snapshots Venom damage rather than recalculating it on delivery", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/gordon_isolation_20260925/gordon_solo_1329l_vs_5000l.json", import.meta.url), "utf8"));+ assert.equal(signedRemainingScore(runOnce(input, loadSimulatorConfig())), -48);});+test("Gordon's second-attack Venom damage lands after Chemical Terror first activates", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_5000l_vs_100l.json", import.meta.url), "utf8"));+ const result = runOnce(input, loadSimulatorConfig());+ assert.equal(signedRemainingScore(result), 4998);+ assert.equal(result.skillReport.attacker.find(skill => skill.skillId === "VenomInfusion")?.skillActivations, 1);+ assert.equal(result.skillReport.attacker.find(skill => skill.skillId === "ChemicalTerror")?.skillActivations, 1);+});++test("Venom's delayed hit ignores the Gatot shield that is up when it is calculated", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/model_checks_20260929/c5_gordon_1000l_vs_gatot_3000i.json", import.meta.url), "utf8"));+ assert.equal(signedRemainingScore(runOnce(input, loadSimulatorConfig())), -2944);+});++test("Venom shares its triggering hit's next-hit curse without consuming another", () => {+ const config = loadSimulatorConfig();+ const probe = (path: string) =>+ JSON.parse(readFileSync(new URL(`../../testcases/emulator_verified/${path}.json`, import.meta.url), "utf8"))[0];+ // The infantry series separates sharing the normal hit's curse from reading the fresh one.+ for (const [path, survivors] of [+ ["gordon_gwen_t9_probe_20260929/gg_1000l_vs_20000t9", -19522],+ ["gordon_gwen_t9_probe_20260929/gg_60i_1000l_vs_20000t9", -19352],+ ["gordon_gwen_t9_probe_20260929/gg_700i_1000l_vs_20000t9", -18333],+ ["gordon_gwen_t9_probe_20260929/gg_1000i_1000l_vs_20000t9", -17781],+ ["model_checks_20260929/c8_gordon_gwen_300l_vs_31000t9l", -30939]+ ] as const) {+ assert.equal(signedRemainingScore(runOnce(probe(path), config)), survivors, path);+ }++ const result = runOnce(probe("gordon_gwen_t9_probe_20260929/gg_1000l_vs_20000t9"), config, { mode: "standard" });+ const hasEagleVision = (attack: { appliedEffects?: AppliedEffect[] } | undefined) =>+ attack?.appliedEffects?.some(effect => effect.effectId === "EagleVision/1") ?? false;+ const turn3 = result.attacks.filter(attack => attack.round === 3 && attack.dealerSide === "attacker");+ const venom = turn3.find(attack => attack.sourceEffectId === "VenomInfusion/1");+ assert.equal(venom?.calculationRound, 2);+ assert.equal(hasEagleVision(venom), true);+ // Venom did not consume the curse its turn-2 attack left, so turn 3's normal hit still gets it.+ assert.equal(hasEagleVision(turn3.find(attack => attack.dealerUnit === "lancer" && !attack.sourceEffectId)), true);+});+test("Gordon boosts Wayne skill damage on Chemical Terror's triggering turn", () => {const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/gordon_interactions_20260925/gordon_wayne_1200l_vs_4800l.json", import.meta.url), "utf8"));assert.equal(signedRemainingScore(runOnce(input, loadSimulatorConfig())), -313);});@@ -54,8 +94,67 @@assert.equal(signedRemainingScore(runOnce(input, config)), survivors, path);}});+test("turn-scheduled Thunder Strike survives Ahmose's Infantry pause", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/ahmose_gordon_renee/ahmose_wayne_vs_jasser.json", import.meta.url), "utf8"));+ const result = runOnce(input, loadSimulatorConfig());+ assert.equal(signedRemainingScore(result), -141);+ assert.equal(result.skillReport.attacker.find(skill => skill.skillId === "ViperFormation")?.skillActivations, 92);+ assert.equal(result.skillReport.attacker.find(skill => skill.skillId === "ThunderStrike")?.skillActivations, 115);+ const pausedRound = result.attacks.filter(attack => attack.round === 20 && attack.dealerSide === "attacker");+ assert.equal(pausedRound.find(attack => attack.kind === "normal")?.cancelReason, "no_attack");+ assert.deepEqual(pausedRound.filter(attack => attack.kind === "skill").map(attack => attack.sourceEffectId), ["ThunderStrike/1"]);+});++test("Sonya's stun suppresses Hendrik's scheduled strike", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/scheduled_skill_stun_20260925/sonya_600l_vs_hendrik_1200m.json", import.meta.url), "utf8"));+ const result = runOnce(input, loadSimulatorConfig());+ assert.equal(signedRemainingScore(result), -422);+ assert.equal(result.extraSkillAttackJobsByEffect["DragonsHeir/1"], 7);+ assert.equal(result.attacks.some(attack => attack.round === 6 && attack.dealerSide === "defender" && attack.kind === "skill"), false);+});++test("an overlapping self-pause cannot override an enemy stun", () => {+ const result = runOnce({+ maxRounds: 1,+ attacker: { troops: { infantry_t1: 1000 }, heroes: { Stop: { skill_1: 1 } } },+ defender: { troops: { infantry_t1: 1000 }, heroes: { Pause: { skill_1: 1, skill_2: 1 } } }+ }, minimalConfig({+ Stop: {+ name: "Stop",+ skills: {+ Stun: {+ trigger: { type: "battle_start" },+ effects: { stun: { type: "no_attack", units: { applies_to: "enemy.infantry" }, duration: { turns: { count: 1 } } } }+ }+ }+ },+ Pause: {+ name: "Pause",+ skills: {+ Rest: {+ trigger: { type: "battle_start" },+ effects: { rest: { type: "no_attack", units: { applies_to: "self.infantry" }, duration: { turns: { count: 1 } } } }+ },+ Volley: {+ trigger: { type: "turn" },+ effects: {+ volley: {+ type: "extra_skill_attack", value: 100,+ units: { applies_to: "self.infantry" },+ trigger_damage_jobs: [{ source: "use.source", target: "use.target" }]+ }+ }+ }+ }+ }+ }));+ assert.equal(result.attacks.find(attack => attack.dealerSide === "defender")?.cancelReason, "no_attack");+ assert.equal(result.attacks.some(attack => attack.dealerSide === "defender" && attack.kind === "skill"), false);+ assert.equal(result.remaining.attacker.infantry, 1000);+});+test("Renee Dreamslice amplifies allied skill damage against the marked target", () => {const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/ahmose_gordon_renee/ahmose_renee_vs_jasser_mark_kind.json", import.meta.url), "utf8"));assert.equal(signedRemainingScore(runOnce(input, loadSimulatorConfig())), 937);});@@ -64,9 +163,21 @@const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/renee_isolation_20260925/renee_mark_source_death.json", import.meta.url), "utf8"));assert.equal(signedRemainingScore(runOnce(input, loadSimulatorConfig())), 184);});-test("Dream Mark capture leaves next-hit vulnerability for Marksmen and delivery precedes the next ordinary attack", () => {+test("stun prevents Dream Mark placement but not delivery of an existing mark", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/renee_stun_20260925/renee_300l_vs_sonya_250l.json", import.meta.url), "utf8"));+ const result = runOnce(input, loadSimulatorConfig());+ assert.equal(signedRemainingScore(result), 61);+ const marks = result.attacks.filter(attack => attack.sourceEffectId === "NightmareTrace/1");+ assert.equal(marks.some(attack => attack.round === 7), false);+ assert.ok(marks.some(attack => attack.round === 11 && attack.kills > 0));+ assert.equal(result.attacks.find(attack =>+ attack.round === 11 && attack.dealerSide === "attacker" && !attack.sourceEffectId+ )?.cancelReason, "no_attack");+});++test("Dream Mark is the turn-start event that consumes the pending next-hit curse and lands before the next turn's attacks", () => {const input: BattleInput = {maxRounds: 3,attacker: {troops: { lancer_t6: 100000, marksman_t6: 100000 },@@ -74,22 +185,49 @@},defender: { troops: { infantry_t6: 1000000 }, heroes: {} }};const result = runOnce(input, loadSimulatorConfig(), { mode: "trace" });- const marksmanHit = result.attacks.find(attack =>- attack.round === 2 && attack.dealerSide === "attacker" && attack.dealerUnit === "marksman"- )!;- assert.ok(marksmanHit.appliedEffects?.some(effect => effect.effectId === "EagleVision/1"));- const nextTurn = result.attacks.filter(attack => attack.round === 3 && attack.dealerSide === "attacker");- assert.equal(nextTurn[0].sourceEffectId, "NightmareTrace/1");- assert.ok(nextTurn[0].appliedEffects?.some(effect => effect.effectId === "EagleVision/1"));- assert.equal(nextTurn[1].sourceEffectId, undefined);- assert.equal(nextTurn[1].appliedEffects?.some(effect => effect.effectId === "EagleVision/1"), false);+ const hasEagleVision = (attack: { appliedEffects?: AppliedEffect[] } | undefined) =>+ attack?.appliedEffects?.some(effect => effect.effectId === "EagleVision/1") ?? false;+ const turn2 = result.attacks.filter(attack => attack.round === 2 && attack.dealerSide === "attacker");+ // The turn-1 marksman curse is taken by Renee's turn-start event, not by the first ordinary hit.+ assert.equal(hasEagleVision(turn2.find(attack => attack.dealerUnit === "lancer" && !attack.sourceEffectId)), false);+ assert.equal(hasEagleVision(turn2.find(attack => attack.dealerUnit === "marksman")), true);+ const turn3 = result.attacks.filter(attack => attack.round === 3 && attack.dealerSide === "attacker");+ assert.equal(turn3[0].sourceEffectId, "NightmareTrace/1");+ assert.equal(turn3[0].calculationRound, 2);+ assert.equal(hasEagleVision(turn3[0]), true);+ assert.equal(hasEagleVision(turn3.find(attack => attack.dealerUnit === "lancer" && !attack.sourceEffectId)), true);});-test("delayed damage settles shields on arrival in recorded Gatot battles", () => {+test("Renee and Gwen per-turn probes match the game when infantry shift the curse chain", () => {const config = loadSimulatorConfig();for (const [path, survivors] of [+ ["rg_1000l_vs_20000t9", -18899],+ ["rg_30i_1000l_vs_20000t9", -18753],+ ["rg_60i_1000l_vs_20000t9", -18616],+ ["rg_200i_1000l_vs_20000t9", -18241],+ ["rg_400i_1000l_vs_20000t9", -17648]+ ] as const) {+ const [input] = JSON.parse(readFileSync(new URL(`../../testcases/emulator_verified/renee_gwen_t9_probe_20260929/${path}.json`, import.meta.url), "utf8"));+ assert.equal(signedRemainingScore(runOnce(input, config)), survivors, path);+ }+});++test("Dream Mark damage lands before Gatot's next shield activates", () => {+ const config = loadSimulatorConfig();+ for (const [path, survivors] of [+ ["renee_shield_saturation_20260926/renee_100l_vs_gatot_50i.json", -37],+ ["renee_shield_saturation_20260926/renee_100l_vs_gatot_100i.json", -91],+ ["gwen_renee_wall_20260926/renee_500l_vs_gatot_300i.json", -229]+ ] as const) {+ const [input] = JSON.parse(readFileSync(new URL(`../../testcases/emulator_verified/${path}`, import.meta.url), "utf8"));+ assert.equal(signedRemainingScore(runOnce(input, config)), survivors, path);+ }+});+test("delayed damage never meets shields in recorded Gatot battles", () => {+ const config = loadSimulatorConfig();+ for (const [path, survivors] of [["renee_s2_bucket_confirmations/gatot_shield_500_150.json", 157],["renee_s2_families/defense_gatot.json", 339]] as const) {const [input] = JSON.parse(readFileSync(new URL(`../../testcases/emulator_verified/${path}`, import.meta.url), "utf8"));@@ -991,9 +1129,9 @@assert.equal(round4LancerAttack?.takerUnit, "marksman");assert.equal((round4LancerAttack?.appliedEffects ?? []).some((effect) => effect.effectId === "mark"), false);});-test("carried extra damage expires when the next normal attack does not match its locked target", () => {+test("turn-start delayed damage lands on its marked target regardless of the next normal target", () => {const result = runOnce({maxRounds: 3,attacker: {@@ -1045,11 +1183,13 @@{ mode: "trace" });const lancerAttacks = result.attacks.filter((attack) => attack.dealerSide === "attacker" && attack.dealerUnit === "lancer");- assert.equal(lancerAttacks.find((attack) => attack.round === 2 && attack.kind === "normal")?.takerUnit, "marksman");- assert.equal(lancerAttacks.find((attack) => attack.round === 3 && attack.kind === "normal")?.takerUnit, "infantry");- assert.equal(lancerAttacks.some((attack) => attack.sourceEffectId === "delayed"), false);+ const ordinary = (round: number) => lancerAttacks.find((attack) => attack.round === round && attack.kind === "normal" && !attack.sourceEffectId);+ assert.equal(ordinary(2)?.takerUnit, "marksman");+ assert.equal(ordinary(3)?.takerUnit, "infantry");+ const delayed = lancerAttacks.filter((attack) => attack.sourceEffectId === "delayed");+ assert.deepEqual(delayed.map((attack) => [attack.round, attack.calculationRound, attack.takerUnit]), [[3, 2, "marksman"]]);});test("carried-damage fixture snapshots normal damage on the even turn and only delivers it next turn", () => {const result = runOnce(@@ -3107,10 +3247,41 @@);assert.deepEqual(result.extraSkillAttackJobsByEffect, { hitAgain: 1 });});+test("engagement effects with engaged_with activate only for the line's engaged class", () => {+ const result = runOnce(+ {+ maxRounds: 1,+ attacker: { troops: { lancer_t1: 1000 }, heroes: { ClassBonus: { skill_1: 1 } } },+ defender: { troops: { infantry_t1: 1000, lancer_t1: 1000 }, heroes: {} }+ },+ minimalConfig({+ ClassBonus: {+ name: "ClassBonus",+ troop_type: "lancer",+ skills: {+ PowerShot: {+ trigger: { type: "engagement", source: "any", target: ["lancer", "infantry"] },+ effects: {+ vsLancer: { type: "type.single_target.damage.up", value: 40, engaged_with: ["lancer"], units: { applies_to: "trigger.source" }, duration: { turns: { count: 1 } } },+ vsInfantry: { type: "type.single_target.damage.up", value: 25, engaged_with: ["infantry"], units: { applies_to: "trigger.source" }, duration: { turns: { count: 1 } } }+ }+ }+ }+ }+ }),+ { mode: "trace" }+ );+ const hit = result.attacks.find(attack => attack.dealerSide === "attacker" && attack.kind === "normal")!;+ assert.equal(hit.takerUnit, "infantry");+ const applied = (hit.appliedEffects ?? []).map(effect => effect.effectId);+ assert.ok(applied.includes("vsInfantry"));+ assert.equal(applied.includes("vsLancer"), false);+});+for (const delayed of [false, true]) {- test(`extra hits apply target modifiers to each actual recipient (${delayed ? "captured" : "immediate"})`, () => {+ test(`an engagement bonus covers all of the line's hits while each recipient's own modifiers apply (${delayed ? "delayed" : "immediate"})`, () => {const splash: Omit<EffectIntentDefinition, "id"> = {type: "extra_skill_attack",value: 100,units: {@@ -3122,22 +3293,27 @@};const result = runOnce({maxRounds: delayed ? 2 : 1,- attacker: { troops: { marksman_t1: 1000000 }, heroes: { MultiTarget: { skill_1: 1, skill_2: 1 } } },+ attacker: { troops: { marksman_t1: 1000000 }, heroes: { MultiTarget: { skill_1: 1, skill_2: 1, skill_3: 1 } } },defender: { troops: { infantry_t1: 1000000, lancer_t1: 1000000, marksman_t1: 1000000 }, heroes: {} }},minimalConfig({MultiTarget: {name: "MultiTarget",troop_type: "marksman",skills: {+ InfantryEngagement: {+ trigger: { type: "engagement", source: "marksman", target: "infantry" },+ effects: {+ infantryBonus: { type: "type.single_target.damage.up", value: 25, units: { applies_to: "trigger.source" }, duration: { turns: { count: 1 } } }+ }+ },TargetModifiers: {trigger: { type: "battle_start" },effects: {- infantryBonus: { type: "type.single_target.damage.up", value: 25, units: { applies_vs: "enemy.infantry" } },- lancerBonus: { type: "type.single_target.damage.up", value: 40, units: { applies_vs: "enemy.lancer" } },- marksmanPenalty: { type: "type.single_target.damage.down", value: 100, units: { applies_vs: "enemy.marksman" } }+ lancerVulnerability: { type: "active.hero.damageTaken.up", value: 40, units: { applies_to: "enemy.lancer" } },+ marksmanResistance: { type: "active.hero.damageTaken.down", value: 100, units: { applies_to: "enemy.marksman" } }}},Splash: {trigger: { type: "turn", first: 1, every: 10 },@@ -3159,14 +3335,15 @@assert.ok(parent);assert.equal(parent.takerUnit, "infantry");const hits = result.attacks.filter(attack => attack.sourceEffectId === "splash");assert.deepEqual(hits.map(hit => hit.takerUnit), UNIT_TYPES);- const factors = { infantry: 1.25, lancer: 1.4, marksman: 0.5 };+ // The Marksmen are engaged with Infantry this turn, so the +25% reaches every recipient.+ const factors = { infantry: 1, lancer: 1.4, marksman: 0.5 };for (const hit of hits) {assert.equal(hit.round, delayed ? 2 : 1);assert.ok(- Math.abs(hit.kills - parent.kills * factors[hit.takerUnit] / 1.25) < 1e-9,- `${hit.takerUnit} casualties must use that recipient's modifiers`+ Math.abs(hit.kills - parent.kills * factors[hit.takerUnit]) < 1e-9,+ `${hit.takerUnit} casualties must keep the attack's class bonus and use that recipient's modifiers`);}});}Index: simulator/src/simulator.ts===================================================================--- simulator/src/simulator.ts prev run+++ simulator/src/simulator.ts this run@@ -14,12 +14,13 @@SimulatorConfig,UnitType} from "./types";import { UNIT_TYPES, unitMaskHas } from "./types";-import { generateDamageJob, deliverDamageJob, ceilIgnoringFloatResidue, minInitialArmy, type DamageResult } from "./damage";+import { appliedNextHitModifiers, generateDamageJob, deliverDamageJob, ceilIgnoringFloatResidue, minInitialArmy, type DamageResult, type NextHitModifier } from "./damage";import { createRecorder, type BattleRecorder } from "./recorder";import {activateEffect,+ compiledTriggerForSkill,advanceEffectAttackDelay,createSeededRng,hasAttackDurationConstraint,isEffectAttackReady,@@ -30,8 +31,9 @@import { buildRuntimeSkills, type RuntimeSkills } from "./runtimeSkills";import { activatePreBattleEffects, buildResolved, prepareBattle, type CompiledBattle } from "./prepare";import {addActiveEffect,+ expireActiveEffect,capJobToRemainingTarget,chargeEffectUse,chargeUsedEffects,chargeUsedEffectsForJob,@@ -39,17 +41,18 @@emptyRoundTargetDamage,materializeDeferredEffects,materializeTriggeredEffects,preparedChancePasses,+ activateScheduledShields,processEffectSchedule,targetExhausted,triggerAttackSkills,triggerSkills,type DamageJobResult,type RunLoopOptions,type Runtime} from "./runtime";-import { captureTriggeredExtraDamage, processExtraAttacks } from "./extraAttacks";+import { calculateDelayedDamage, landDelayedDamage, processExtraAttacks } from "./extraAttacks";// Re-exported so the public battle API stays importable from one module.export { prepareBattle, type CompiledBattle } from "./prepare";import { emptyTroops, resolveFighter } from "./fighterResolution";@@ -78,8 +81,9 @@interface Control {effect: ActiveEffect;reason: "dodge" | "no_attack";attackDurationEffects: ActiveEffect[];+ blocksTurnAttacks: boolean;}function bearFighterInput(): FighterInput {return {@@ -249,15 +253,25 @@for (let round = 1; round <= maxRounds; round += 1) {if (winnerFor(runtime.troops)) break;rounds = round;const roundStartTroops = snapshotTroops(runtime.troops);- processEffectSchedule(runtime, round);- triggerRoundStartSkills(round, runtime, recorder);-const intents: AttackIntent[] = [];const results: DamageJobResult[] = [];const cancelled: CancelledAttack[] = [];const roundTargetDamage = emptyRoundTargetDamage();++ // Turn start: delayed hits settled earlier apply their kills; last turn's effects expire+ // and this turn's activate; turn-trigger skills act; then scheduled shields go up.+ landDelayedDamage(round, runtime, roundStartTroops, roundTargetDamage, loopOptions, recorder, results);+ if (loopOptions.scoreSide) score += scoreFor(results, loopOptions.scoreSide);+ // Attacks are still declared against targets alive in the turn's snapshot; landed+ // kills only cap what those attacks can remove.+ const landedTargetDamage = snapshotTroops(roundTargetDamage);+ processEffectSchedule(runtime, round);+ triggerRoundStartSkills(round, runtime, recorder);+ activateEngagementSkills(round, runtime, recorder, roundStartTroops);+ fireTurnStartCarriers(round, fighters, runtime, recorder, damageJobOptions, roundStartTroops);+ activateScheduledShields(runtime, round);// Resolve each normal attack as one procedural cluster. Later attacks observe effects// produced by earlier attacks; no synthetic global attack-declaration phase exists.const orderIndexBySide: Record<SideId, number> = { attacker: 0, defender: 0 };for (const dealerUnit of UNIT_TYPES) {@@ -284,9 +298,9 @@recorder.recordBattleOrder(intent, ordered.effect, takerUnit);}const job = normalJob(intent, roundStartTroops);- if (loopOptions.capRoundKills && targetExhausted(job, roundStartTroops, roundTargetDamage)) continue;+ if (loopOptions.capRoundKills && targetExhausted(job, roundStartTroops, roundTargetDamage, landedTargetDamage)) continue;// A pre-existing no_attack prevents the attack from being declared at all.// Reactive dodge skills instead roll on this declaration and can dodge this job.const noAttack = applicableControl(job, runtime, "no_attack");@@ -295,16 +309,17 @@runtime.attackControlCounts.no_attack += 1;materializeTriggeredEffects(control.effect, round, intent, runtime, recorder);if (useEffectsOnCancel.no_attack) chargeCancelledAttack(job, control.effect, control.attackDurationEffects, runtime);cancelled.push({ intent, control });+ if (!control.blocksTurnAttacks) {+ const extraAttacks = processExtraAttacks("cancelled", job, intent, runtime, fighters, damageJobOptions, roundTargetDamage, loopOptions, results);+ if (loopOptions.scoreSide && job.dealerSide === loopOptions.scoreSide.dealerSide && job.takerSide === loopOptions.scoreSide.takerSide) {+ score += extraAttacks.totalKills;+ }+ }continue;}- const pendingAttacks = processExtraAttacks("pending", job, intent, runtime, fighters, damageJobOptions, roundTargetDamage, loopOptions, results);- if (loopOptions.scoreSide && job.dealerSide === loopOptions.scoreSide.dealerSide && job.takerSide === loopOptions.scoreSide.takerSide) {- score += pendingAttacks.totalKills;- }-const matchingTriggerSkills = runtime.skills.attackDeclaredByJobShape[damageJobShapeSlot("normal", intent.dealerSide, intent.dealerUnit, intent.takerSide, intent.takerUnit)];const deferredEffects = matchingTriggerSkills@@ -313,8 +328,9 @@const dodge = applicableControl(job, runtime, "dodge");const triggeredChildren = fireApplicableCarriers(round, job, intent, runtime, recorder);let normalKills = 0;+ let normalNextHit: NextHitModifier[] = [];if (dodge) {runtime.attackControlCounts.dodge += 1;materializeTriggeredEffects(dodge.effect, round, intent, runtime, recorder);if (useEffectsOnCancel.dodge) chargeCancelledAttack(job, dodge.effect, dodge.attackDurationEffects, runtime);@@ -326,13 +342,16 @@normalKills = normalResult.kills;if (loopOptions.scoreSide && job.dealerSide === loopOptions.scoreSide.dealerSide && job.takerSide === loopOptions.scoreSide.takerSide) {score += normalResult.kills;}+ // Read before charging: expiring next-hit effects leave their groups.+ normalNextHit = appliedNextHitModifiers(runtime.usedEffects, round);chargeUsedEffectsForJob(runtime, job, recorder);results.push({ job, result: normalResult, intent });}- captureTriggeredExtraDamage(triggeredChildren, job, fighters, damageJobOptions, runtime);+ // Extra damage attached to this attack shares its normal hit's next-hit modifiers.+ calculateDelayedDamage(triggeredChildren, job, fighters, damageJobOptions, runtime, normalNextHit);advanceNormalAttackCounters(intent, runtime);const extraAttacks = processExtraAttacks("immediate", job, intent, runtime, fighters, damageJobOptions, roundTargetDamage, loopOptions, results);if (loopOptions.scoreSide && job.dealerSide === loopOptions.scoreSide.dealerSide && job.takerSide === loopOptions.scoreSide.takerSide) {score += extraAttacks.totalKills;@@ -477,17 +496,20 @@reason: Control["reason"]): Control | undefined {const attackDurationEffects: ActiveEffect[] = [];let selected: Control | undefined;+ let blocksTurnAttacks = false;for (const effect of runtime.effectIndex.controls) {if (controlType(effect) !== reason) continue;if (!controlEffectApplies(effect, job, reason)) continue;if (!advanceEffectAttackDelay(effect)) continue;if (hasAttackDurationConstraint(effect)) attackDurationEffects.push(effect);+ blocksTurnAttacks ||= reason === "no_attack" && effect.ownerSide !== job.dealerSide;selected = {effect,reason,- attackDurationEffects+ attackDurationEffects,+ blocksTurnAttacks};}return selected;}@@ -537,8 +559,98 @@}return children;}+// Each living line settles its target at turn start (after turn skills such as Ambusher reorder+// it). Engagement skills fire for lines engaged with their trigger target, e.g. Charge for+// Lancers engaging Marksmen; their effects cover the line's whole turn.+function activateEngagementSkills(+ round: number,+ runtime: Runtime,+ recorder: BattleRecorder,+ roundStartTroops: DamageJob["roundStartTroops"]+): void {+ for (const { skill, probabilityPct } of runtime.skills.engagement) {+ const trigger = compiledTriggerForSkill(skill);+ const side = trigger.source.side;+ for (const dealerUnit of UNIT_TYPES) {+ if (!unitMaskHas(trigger.source.units, dealerUnit)) continue;+ const takerUnit = engagedTarget(dealerUnit, side, runtime, roundStartTroops);+ if (!takerUnit || trigger.target.side !== oppositeSide(side) || !unitMaskHas(trigger.target.units, takerUnit)) continue;+ recorder.recordSkillTriggerAttempt(skill);+ if (!preparedChancePasses(probabilityPct, runtime.rng)) continue;+ recorder.recordSkillTriggered(skill);+ const intent = makeNormalIntent(round, side, dealerUnit, oppositeSide(side), takerUnit, 0, runtime);+ for (const effectIntent of skill.effects) {+ if (effectIntent.engaged_with && !effectIntent.engaged_with.includes(takerUnit)) continue;+ addActiveEffect(runtime, activateEffect(skill, effectIntent, round, intent));+ runtime.effectActivationCounts[skill.side] += 1;+ recorder.recordSkillEffectActivated(skill);+ }+ }+ }+}++/** The unit a living line targets this turn, as its normal attack will; undefined if it cannot act. */+function engagedTarget(+ dealerUnit: UnitType,+ side: SideId,+ runtime: Runtime,+ roundStartTroops: DamageJob["roundStartTroops"]+): UnitType | undefined {+ if (ceilIgnoringFloatResidue(roundStartTroops[side][dealerUnit] ?? 0) <= 0) return undefined;+ const ordered = orderFromEffects(dealerUnit, side, runtime.effectIndex, false);+ return firstLivingUnit(ordered?.order ?? UNIT_TYPES, oppositeSide(side), roundStartTroops);+}++// Carriers created by turn-triggered skills act at turn start, before any attack: the first+// living unit they apply to uses them at once against its current target, so a delayed hit+// they spawn is the next damage event for any live next-hit modifier. A unit under an enemy+// no_attack control cannot act, and an unused turn carrier is discarded either way.+function fireTurnStartCarriers(+ round: number,+ fighters: Record<SideId, ResolvedFighter>,+ runtime: Runtime,+ recorder: BattleRecorder,+ damageJobOptions: Parameters<typeof calculateDelayedDamage>[3],+ roundStartTroops: DamageJob["roundStartTroops"]+): void {+ const carriers = runtime.effectIndex.carriers.filter((carrier) =>+ carrier.createdRound === round && carrier.sourceSkill?.trigger.type === "turn"+ );+ for (const carrier of carriers) {+ const side = carrier.appliesTo.side;+ const dealerUnit = UNIT_TYPES.find((unit) =>+ unitMaskHas(carrier.appliesTo.units, unit) && ceilIgnoringFloatResidue(roundStartTroops[side][unit] ?? 0) > 0+ );+ const takerSide = oppositeSide(side);+ const takerUnit = dealerUnit ? engagedTarget(dealerUnit, side, runtime, roundStartTroops) : undefined;+ if (!dealerUnit || !takerUnit || !unitMaskHas(carrier.appliesVs.units, takerUnit) || blockedByEnemyControl(runtime, side, dealerUnit)) {+ expireActiveEffect(runtime, carrier);+ continue;+ }+ const intent = makeNormalIntent(round, side, dealerUnit, takerSide, takerUnit, 0, runtime);+ const children = materializeTriggeredEffects(carrier, round, intent, runtime, recorder);+ chargeEffectUse(runtime, carrier);+ calculateDelayedDamage(children, normalJob(intent, roundStartTroops), fighters, damageJobOptions, runtime);+ }+}++function blockedByEnemyControl(runtime: Runtime, side: SideId, unit: UnitType): boolean {+ return runtime.effectIndex.controls.some((effect) =>+ controlType(effect) === "no_attack" && effect.ownerSide !== side &&+ effect.appliesTo.side === side && unitMaskHas(effect.appliesTo.units, unit) && isEffectAttackReady(effect)+ );+}++function scoreFor(results: DamageJobResult[], scoreSide: NonNullable<RunLoopOptions["scoreSide"]>): number {+ let kills = 0;+ for (const { job, result } of results) {+ if (job.dealerSide === scoreSide.dealerSide && job.takerSide === scoreSide.takerSide) kills += result.kills;+ }+ return kills;+}+function advanceNormalAttackCounters(intent: AttackIntent, runtime: Runtime): void {runtime.counters.attacks[intent.dealerSide][intent.dealerUnit] += 1;runtime.counters.received[intent.takerSide][intent.takerUnit] += 1;}Index: simulator/src/tooling/testcases.test.ts===================================================================--- simulator/src/tooling/testcases.test.ts prev run+++ simulator/src/tooling/testcases.test.ts this run@@ -25,44 +25,49 @@assert.ok(files.some((file) => file.endsWith("emulator_verified/jasser_solo.json.disabled")));assert.ok(files.some((file) => file.endsWith("emulator_verified/reina_logan_combo_v2.json.stale_troops")));});-test("discoverTestcaseFiles matches filenames or heroes on either side, including joiners", (t) => {- const testcaseRoot = tempDir("simulator-hero-matching");+test("discoverTestcaseFiles matches filenames and participating heroes, but not directories or descriptions", (t) => {+ const testcaseRoot = tempDir("simulator-directory-matching");t.after(() => rmSync(testcaseRoot, { recursive: true, force: true }));const fixtures = {"attacker.json": { attacker: { heroes: { Gwen: {} } } },"defender.json": [{}, { defender: { heroes: { Gwen: {} } } }],"attacker-joiner.json": { attacker: { joiner_heroes: { Gwen: {} } } },"defender-joiner.json": { defender: { joiner_heroes: { Gwen: {} } } },+ "array-heroes.json": { attacker: { heroes: [{ name: "Gwen" }] } },+ "array-joiners.json": { defender: { joiner_heroes: [{ name: "Gwen" }] } },"unrelated.json": { description: "Gwen", attacker: { heroes: { Sergey: {} } } },- "disabled.json.disabled": { attacker: { heroes: { Gwen: {} } } },- "stale.json.stale_troops": { defender: { heroes: { Gwen: {} } } },+ "Gwen-disabled.json.disabled": { attacker: { heroes: { Gwen: {} } } },+ "Gwen-stale.json.stale_troops": { defender: { heroes: { Gwen: {} } } },};for (const [file, entry] of Object.entries(fixtures)) {writeFileSync(resolve(testcaseRoot, file), JSON.stringify(entry));}writeFileSync(resolve(testcaseRoot, "Gwen-invalid.json"), "{");writeFileSync(resolve(testcaseRoot, "invalid.json"), "{");- const expected = [- "Gwen-invalid.json", "attacker-joiner.json", "attacker.json",- "defender-joiner.json", "defender.json",- ];+ mkdirSync(resolve(testcaseRoot, "Gwen"));+ writeFileSync(resolve(testcaseRoot, "Gwen", "other.json"), "{}");+ writeFileSync(resolve(testcaseRoot, "Gwen", "Gwen-nested.json"), "{}");++ const expected = ["Gwen-invalid.json", "Gwen/Gwen-nested.json", "attacker.json", "defender.json",+ "attacker-joiner.json", "defender-joiner.json", "array-heroes.json", "array-joiners.json"];assert.deepEqual(- discoverTestcaseFiles({ testcaseRoot, matching: "Gwe" }),+ discoverTestcaseFiles({ testcaseRoot, matching: "gwe" }),expected.map((file) => resolve(testcaseRoot, file)).sort(),);assert.deepEqual(discoverTestcaseFiles({ testcaseRoot, matching: "Gwe", includeDisabled: true }),- [...expected, "disabled.json.disabled", "stale.json.stale_troops"]+ [...expected, "Gwen-disabled.json.disabled", "Gwen-stale.json.stale_troops"].map((file) => resolve(testcaseRoot, file)).sort(),);assert.deepEqual(discoverTestcaseFiles({ testcaseRoot, matching: "unrelated" }),[resolve(testcaseRoot, "unrelated.json")],);assert.deepEqual(discoverTestcaseFiles({ testcaseRoot, matching: "missing" }), []);+ assert.deepEqual(discoverTestcaseFiles({ testcaseRoot, matching: "simulator-directory-matching" }), []);});test("runTestcases returns compact summary entries and full detail entries separately", () => {const config = loadSimulatorConfig();Index: simulator/src/tooling/testcases.ts===================================================================--- simulator/src/tooling/testcases.ts prev run+++ simulator/src/tooling/testcases.ts this run@@ -1,6 +1,6 @@import { readdirSync, readFileSync, statSync } from "node:fs";-import { dirname, relative, resolve } from "node:path";+import { basename, dirname, relative, resolve } from "node:path";import { fileURLToPath } from "node:url";import {loadCalibrationComparison,@@ -199,34 +199,38 @@export function discoverTestcaseFiles(options: Pick<TestcaseRunOptions, "testcaseRoot" | "matching" | "includeDisabled"> = {}): string[] {const root = resolve(options.testcaseRoot ?? defaultTestcaseRoot());const files: string[] = [];walk(root, files);+ const matching = options.matching?.toLowerCase();return files.filter((file) => isDiscoverableTestcaseFile(file, options.includeDisabled)).filter((file) => options.includeDisabled || (!file.endsWith(".disabled") && !file.endsWith(".stale_troops")))- .filter((file) => !options.matching || file.includes(options.matching) || fileHeroesMatch(file, options.matching))+ .filter((file) => {+ if (!matching || basename(file).toLowerCase().includes(matching)) return true;+ let parsed: unknown;+ try {+ parsed = JSON.parse(readFileSync(file, "utf8"));+ } catch {+ return false;+ }+ const entries = Array.isArray(parsed) ? parsed : [parsed];+ return entries.some((entry) => {+ const testcase = asObject(entry);+ for (const side of ["attacker", "defender"]) {+ const fighter = asObject(testcase[side]);+ for (const collection of [fighter.heroes, fighter.joiner_heroes]) {+ const names = Array.isArray(collection)+ ? collection.map((hero) => asObject(hero).name)+ : Object.keys(asObject(collection));+ if (names.some((name) => typeof name === "string" && name.toLowerCase().includes(matching))) return true;+ }+ }+ return false;+ });+ }).sort();}-function fileHeroesMatch(file: string, matching: string): boolean {- let parsed: unknown;- try {- parsed = JSON.parse(readFileSync(file, "utf8"));- } catch {- return false;- }- const entries = Array.isArray(parsed) ? parsed : [parsed];- return entries.some((entry) => {- const testcase = asObject(entry);- return [testcase.attacker, testcase.defender].some((side) => {- const army = asObject(side);- return [army.heroes, army.joiner_heroes].some((heroes) =>- Object.keys(asObject(heroes)).some((name) => name.includes(matching)),- );- });- });-}-export function runTestcases(options: TestcaseRunOptions, config: SimulatorConfig): TestcaseRunReport {const prepared = prepareTestcaseCases(options);return runPreparedTestcases(options, config, prepared, (job) => executeTestcaseCase(job, config));}@@ -483,20 +487,25 @@averageRounds: number;deterministic: boolean;thresholds?: Record<string, number>;exact?: boolean;+ maxAdjustment?: number;}): InternalStatAdjustment | undefined {+ // The search value is the shift of the finest-rounded stat; each coarser stat moves in+ // proportion to its own rounding bound (see statRoundingBound).let maxAdjustment = STAT_ROUNDING_MAX_ADJUSTMENT;for (const fighter of [options.input.attacker, options.input.defender]) {for (const stats of Object.values(fighter.stats ?? {}) as Array<Partial<StatBlock>>) {for (const key of ["attack", "defense", "lethality", "health"] as const) {const value = stats[key];if (value === undefined) continue;- if (Math.abs(value * 100 - Math.round(value * 100)) > 1e-9) return undefined;- if (Math.abs(value * 10 - Math.round(value * 10)) > 1e-9) maxAdjustment = 0.005;+ const bound = statRoundingBound(value);+ if (bound === undefined) return undefined;+ maxAdjustment = Math.min(maxAdjustment, bound);}}}+ options = { ...options, maxAdjustment };// Deterministic cases correct any nonzero bias; stochastic cases correct only outright misses.// Either way a nonzero bias is needed to pick a search direction.const shouldCorrect = options.deterministic ? options.game.bias_raw !== 0 : !options.game.passes;if (!shouldCorrect || options.game.bias_raw === 0) return undefined;@@ -539,10 +548,11 @@averageRounds: number;deterministic: boolean;thresholds?: Record<string, number>;exact?: boolean;+ maxAdjustment?: number;}, value: number): InternalStatAdjustment {- const adjustedInput = inputWithStatAdjustment(options.input, value);+ const adjustedInput = inputWithStatAdjustment(options.input, value, options.maxAdjustment ?? STAT_ROUNDING_MAX_ADJUSTMENT);const candidateSamples = simulateAdjustedOutcomes(adjustedInput, options.job, options.config);const adjusted = compareOutcomeDistribution({candidate: { samples: candidateSamples },reference: { samples: options.reference },@@ -596,24 +606,31 @@}return samples;}-function inputWithStatAdjustment(input: BattleInput, value: number): BattleInput {+function inputWithStatAdjustment(input: BattleInput, value: number, finestBound: number): BattleInput {const adjusted = structuredClone(input);- adjustFighterStats(adjusted.attacker, value);- adjustFighterStats(adjusted.defender, -value);+ adjustFighterStats(adjusted.attacker, value, finestBound);+ adjustFighterStats(adjusted.defender, -value, finestBound);return adjusted;}-function adjustFighterStats(fighter: FighterInput, value: number): void {+function adjustFighterStats(fighter: FighterInput, value: number, finestBound: number): void {for (const stats of Object.values(fighter.stats ?? {}) as Array<Partial<StatBlock>>) {for (const key of ["attack", "defense", "lethality", "health"] as Array<keyof StatBlock>) {if (stats[key] === undefined) continue;- stats[key] = roundStatAdjustment(Number(stats[key]) + value);+ const bound = statRoundingBound(Number(stats[key])) ?? finestBound;+ stats[key] = roundStatAdjustment(Number(stats[key]) + value * (bound / finestBound));}}}+/** Half the display step of a stat shown to at most two decimals; undefined for finer values. */+function statRoundingBound(value: number): number | undefined {+ if (Math.abs(value * 100 - Math.round(value * 100)) > 1e-9) return undefined;+ return Math.abs(value * 10 - Math.round(value * 10)) > 1e-9 ? 0.005 : STAT_ROUNDING_MAX_ADJUSTMENT;+}+function adjustmentMode(adjusted: ParityComparisonMetrics, deterministic: boolean): TestcaseStatAdjustment["mode"] {if (deterministic) {if (adjusted.bias_raw === 0) return "deterministic_exact";if (Math.abs(adjusted.bias_raw) <= 1) return "deterministic_within_one";Index: simulator/src/types.ts===================================================================--- simulator/src/types.ts prev run+++ simulator/src/types.ts this run@@ -1,6 +1,4 @@-import type { GeneratedDamage } from "./damage";-export type SideId = "attacker" | "defender";export type UnitType = "infantry" | "lancer" | "marksman";export type DamageKind = "normal" | "skill";export type UnitMask = number;@@ -96,8 +94,10 @@/** Restrict this modifier to these damage job kinds without changing its arithmetic bucket. */applies_to_damage_kinds?: DamageKind[];/** Apply this modifier only while the named effect is applicable to the same damage job. */requires_effect?: string;+ /** Engagement skills only: activate this effect only for a line engaged with one of these units. */+ engaged_with?: UnitType[];value_formula?: PercentOfValueFormula;value_evolution?: { type?: string; step?: string; value?: number };units?: Record<string, unknown>;trigger_damage_jobs?: TriggerDamageJobDefinition[];@@ -289,10 +289,11 @@// Index into RuntimeSkills.effectGroups and every runtime's liveEffectsByGroup.ordinal: number;bucketIndex: number;sameEffectStacking: SameEffectStacking;- /** Taker-side attack budgets are sampled when captured damage lands, not when it is generated. */- attackLimitedTakerModifier: boolean;+ // Attack-count-limited target-side modifier (e.g. Gwen's Eagle Vision): a "next hit"+ // debuff consumed by the damage events it applies to.+ nextHit?: boolean;// Prepared dependency lookup indexed by damage-job shape. An empty slot means the// required effect cannot apply to that job, so this group must not contribute.requiredGroupOrdinalsByJobShape?: Array<number[] | undefined>;}@@ -329,10 +330,8 @@// unless useEffectsOnDodge/useEffectsOnNoAttack disable that.uses: number;sameEffectStacking: SameEffectStacking;triggerEffects?: ResolvedEffectIntentDefinition[];- /** Generation-time damage awaiting shield settlement on its later matching attack. */- pendingDamageJobs?: PendingDamageJob[];effectGroup?: ActiveEffectGroup;effectGroupPosition?: number;}@@ -377,13 +376,8 @@appliedEffects?: AppliedEffect[];trace?: DamageEquationTrace;}-export interface PendingDamageJob {- job: DamageJob;- generated: GeneratedDamage;-}-export interface CounterDelta {side: SideId;unit: UnitType;counter: "attacks" | "received_attacks";Index: simulator/tsconfig.json===================================================================--- simulator/tsconfig.json prev run+++ simulator/tsconfig.json this run@@ -2,8 +2,9 @@"compilerOptions": {"target": "ES2022","module": "ESNext","moduleResolution": "Bundler",+ "types": ["node"],"strict": true,"esModuleInterop": true,"resolveJsonModule": true,"forceConsistentCasingInFileNames": true,Index: testcases/emulator_verified/ahmose_gordon_fresh_20260925/ahmose_gordon_75i300l_vs_wuming_225i75l75m.json===================================================================--- testcases/emulator_verified/ahmose_gordon_fresh_20260925/ahmose_gordon_75i300l_vs_wuming_225i75l75m.json prev run+++ testcases/emulator_verified/ahmose_gordon_fresh_20260925/ahmose_gordon_75i300l_vs_wuming_225i75l75m.json this run@@ -0,0 +1,189 @@+[+ {+ "test_id": "ahmose_gordon_75i300l_vs_wuming_225i75l75m",+ "description": "C2 battle report 2734693171367029",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Ahmose": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 75,+ "lancer_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 417.61,+ "defense": 410.61,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 488.62,+ "defense": 492.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 225,+ "lancer_t6": 75,+ "marksman_t6": 75+ },+ "stats": {+ "infantry": {+ "attack": 453.71,+ "defense": 446.26,+ "lethality": 223.57,+ "health": 274.97+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T22:15:42.000Z",+ "randomseed": 1790374543,+ "attacker": 35,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171367029",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T22-15-59.133Z-248ee93c-918e-4414-b7c0-4bc53c36380d.json",+ "winner": "attacker",+ "attacker": {+ "troops": 375,+ "survivors": 35,+ "losses": 0,+ "injured": 120,+ "lightly_injured": 220,+ "kills": 133+ },+ "defender": {+ "troops": 375,+ "survivors": 0,+ "losses": 0,+ "injured": 133,+ "lightly_injured": 242,+ "kills": 120+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 75,+ "survivors": 0,+ "losses": 0,+ "injured": 27,+ "lightly_injured": 48,+ "kills": 5+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 35,+ "losses": 0,+ "injured": 93,+ "lightly_injured": 172,+ "kills": 128+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 225,+ "survivors": 0,+ "losses": 0,+ "injured": 79,+ "lightly_injured": 146,+ "kills": 25+ },+ "lancer_t6": {+ "troops": 75,+ "survivors": 0,+ "losses": 0,+ "injured": 27,+ "lightly_injured": 48,+ "kills": 38+ },+ "marksman_t6": {+ "troops": 75,+ "survivors": 0,+ "losses": 0,+ "injured": 27,+ "lightly_injured": 48,+ "kills": 57+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Ahmose": {+ "Viper Formation": {+ "triggered": 5,+ "displayed_kills": null+ }+ },+ "Gordon": {+ "Venom Infusion": {+ "triggered": 34,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 22,+ "displayed_kills": null+ },+ "Toxic Release": {+ "triggered": 17,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_150l_vs_wuming_60i20l20m.json===================================================================--- testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_150l_vs_wuming_60i20l20m.json prev run+++ testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_150l_vs_wuming_60i20l20m.json this run@@ -0,0 +1,168 @@+[+ {+ "test_id": "gordon_150l_vs_wuming_60i20l20m",+ "description": "C2 battle report 2734693171367082",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 488.62,+ "defense": 492.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 60,+ "lancer_t6": 20,+ "marksman_t6": 20+ },+ "stats": {+ "infantry": {+ "attack": 453.71,+ "defense": 446.26,+ "lethality": 223.57,+ "health": 274.97+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T22:22:10.000Z",+ "randomseed": 1790374931,+ "attacker": 38,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171367082",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T22-22-27.137Z-0438a9a8-3944-4192-acf7-3bd12fa8eee4.json",+ "winner": "attacker",+ "attacker": {+ "troops": 150,+ "survivors": 38,+ "losses": 0,+ "injured": 40,+ "lightly_injured": 72,+ "kills": 35+ },+ "defender": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 40+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 150,+ "survivors": 38,+ "losses": 0,+ "injured": 40,+ "lightly_injured": 72,+ "kills": 35+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 60,+ "survivors": 0,+ "losses": 0,+ "injured": 21,+ "lightly_injured": 39,+ "kills": 10+ },+ "lancer_t6": {+ "troops": 20,+ "survivors": 0,+ "losses": 0,+ "injured": 7,+ "lightly_injured": 13,+ "kills": 13+ },+ "marksman_t6": {+ "troops": 20,+ "survivors": 0,+ "losses": 0,+ "injured": 7,+ "lightly_injured": 13,+ "kills": 17+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": 14,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 29,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 19,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_300l_vs_1000i.json===================================================================--- testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_300l_vs_1000i.json prev run+++ testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_300l_vs_1000i.json this run@@ -0,0 +1,143 @@+[+ {+ "test_id": "gordon_300l_vs_1000i",+ "description": "C2 battle report 2734693171367011",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 488.62,+ "defense": 492.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T22:11:08.000Z",+ "randomseed": 1790374269,+ "attacker": 0,+ "defender": 264,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171367011",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T22-11-25.132Z-d4928481-407f-42db-85dd-b73090d96efd.json",+ "winner": "defender",+ "attacker": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 258+ },+ "defender": {+ "troops": 1000,+ "survivors": 264,+ "losses": 0,+ "injured": 258,+ "lightly_injured": 478,+ "kills": 105+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 258+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 264,+ "losses": 0,+ "injured": 258,+ "lightly_injured": 478,+ "kills": 105+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": 35,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 70,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 46,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_300l_vs_1200m.json===================================================================--- testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_300l_vs_1200m.json prev run+++ testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_300l_vs_1200m.json this run@@ -0,0 +1,143 @@+[+ {+ "test_id": "gordon_300l_vs_1200m",+ "description": "C2 battle report 2734693171367016",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 488.62,+ "defense": 492.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "marksman_t6": 1200+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T22:12:16.000Z",+ "randomseed": 1790374337,+ "attacker": 0,+ "defender": 69,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171367016",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T22-12-33.126Z-6fc5dfc9-6262-4f44-9fb0-f65ff578b024.json",+ "winner": "defender",+ "attacker": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 396+ },+ "defender": {+ "troops": 1200,+ "survivors": 69,+ "losses": 0,+ "injured": 396,+ "lightly_injured": 735,+ "kills": 105+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 396+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1200,+ "survivors": 69,+ "losses": 0,+ "injured": 396,+ "lightly_injured": 735,+ "kills": 105+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": 12,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 24,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 16,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_5000l_vs_100l.json===================================================================--- testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_5000l_vs_100l.json prev run+++ testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_5000l_vs_100l.json this run@@ -0,0 +1,143 @@+[+ {+ "test_id": "gordon_5000l_vs_100l",+ "description": "C2 battle report 2734693171367273",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 5000+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 488.62,+ "defense": 492.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T22:31:22.000Z",+ "randomseed": 1790375483,+ "attacker": 4998,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171367273",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T22-31-39.119Z-8a72c006-02b4-45c2-a073-4c9c5a63e6fb.json",+ "winner": "attacker",+ "attacker": {+ "troops": 5000,+ "survivors": 4998,+ "losses": 0,+ "injured": 1,+ "lightly_injured": 1,+ "kills": 35+ },+ "defender": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 1+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 5000,+ "survivors": 4998,+ "losses": 0,+ "injured": 1,+ "lightly_injured": 1,+ "kills": 35+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 1+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": null,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 1,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_5000l_vs_300l.json===================================================================--- testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_5000l_vs_300l.json prev run+++ testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_5000l_vs_300l.json this run@@ -0,0 +1,143 @@+[+ {+ "test_id": "gordon_5000l_vs_300l",+ "description": "C2 battle report 2734693171367233",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 5000+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 488.62,+ "defense": 492.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T22:29:28.000Z",+ "randomseed": 1790375369,+ "attacker": 4991,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171367233",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T22-29-45.119Z-df1567ac-9079-4e43-a43a-1f9157e8824d.json",+ "winner": "attacker",+ "attacker": {+ "troops": 5000,+ "survivors": 4991,+ "losses": 0,+ "injured": 4,+ "lightly_injured": 5,+ "kills": 105+ },+ "defender": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 4+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 5000,+ "survivors": 4991,+ "losses": 0,+ "injured": 4,+ "lightly_injured": 5,+ "kills": 105+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 4+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": null,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 1,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_50i200l_vs_wuming_150i50l50m.json===================================================================--- testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_50i200l_vs_wuming_150i50l50m.json prev run+++ testcases/emulator_verified/ahmose_gordon_fresh_20260925/gordon_50i200l_vs_wuming_150i50l50m.json this run@@ -0,0 +1,177 @@+[+ {+ "test_id": "gordon_50i200l_vs_wuming_150i50l50m",+ "description": "C2 battle report 2734693171367045",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 50,+ "lancer_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 488.62,+ "defense": 492.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 150,+ "lancer_t6": 50,+ "marksman_t6": 50+ },+ "stats": {+ "infantry": {+ "attack": 453.71,+ "defense": 446.26,+ "lethality": 223.57,+ "health": 274.97+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T22:17:30.000Z",+ "randomseed": 1790374651,+ "attacker": 0,+ "defender": 126,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171367045",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T22-17-47.116Z-9911b10d-705f-4f44-9884-8ddab46a485e.json",+ "winner": "defender",+ "attacker": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 44+ },+ "defender": {+ "troops": 250,+ "survivors": 126,+ "losses": 0,+ "injured": 44,+ "lightly_injured": 80,+ "kills": 88+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 1+ },+ "lancer_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 43+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 150,+ "survivors": 26,+ "losses": 0,+ "injured": 44,+ "lightly_injured": 80,+ "kills": 21+ },+ "lancer_t6": {+ "troops": 50,+ "survivors": 50,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 29+ },+ "marksman_t6": {+ "troops": 50,+ "survivors": 50,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 38+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": 14,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 29,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 19,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/attdef_test_minxxx_attacks_nc.json===================================================================--- testcases/emulator_verified/attdef_test_minxxx_attacks_nc.json prev run+++ testcases/emulator_verified/attdef_test_minxxx_attacks_nc.json this run@@ -64,9 +64,9 @@"health": 28.8},"mark": {"attack": 83.3,- "defense": 0.0,+ "defense": 69.9,"lethality": 37.6,"health": 29.4}},Index: testcases/emulator_verified/extra_damage_source_death_20260926/calibration_gwen.json===================================================================--- testcases/emulator_verified/extra_damage_source_death_20260926/calibration_gwen.json prev run+++ testcases/emulator_verified/extra_damage_source_death_20260926/calibration_gwen.json this run@@ -0,0 +1,175 @@+[+ {+ "test_id": "calibration_gwen",+ "description": "C2 battle report 2734693171388824",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 1000,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Hendrik": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 1000,+ "marksman_t6": 500+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 479,+ "defense": 467.8,+ "lethality": 244.2,+ "health": 221.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T11:07:13.000Z",+ "randomseed": 1790420834,+ "attacker": 0,+ "defender": 1191,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171388824",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T11-07-31.130Z-530733f4-c708-48a6-a140-bbe22964fa98.json",+ "winner": "defender",+ "attacker": {+ "troops": 1100,+ "survivors": 0,+ "losses": 0,+ "injured": 385,+ "lightly_injured": 715,+ "kills": 109+ },+ "defender": {+ "troops": 1500,+ "survivors": 1191,+ "losses": 0,+ "injured": 109,+ "lightly_injured": 200,+ "kills": 385+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 54+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 55+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 696,+ "losses": 0,+ "injured": 107,+ "lightly_injured": 197,+ "kills": 42+ },+ "marksman_t6": {+ "troops": 500,+ "survivors": 495,+ "losses": 0,+ "injured": 2,+ "lightly_injured": 3,+ "kills": 343+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 11,+ "displayed_kills": 3+ },+ "Blastmaster": {+ "triggered": 4,+ "displayed_kills": 2+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 14,+ "displayed_kills": 57+ },+ "Armor of Barnacles": {+ "triggered": 11,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/extra_damage_source_death_20260926/calibration_renee.json===================================================================--- testcases/emulator_verified/extra_damage_source_death_20260926/calibration_renee.json prev run+++ testcases/emulator_verified/extra_damage_source_death_20260926/calibration_renee.json this run@@ -0,0 +1,144 @@+[+ {+ "test_id": "calibration_renee",+ "description": "C2 battle report 2734693171388819",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 300,+ "marksman_t6": 500+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T11:06:53.000Z",+ "randomseed": 1790420814,+ "attacker": 728,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171388819",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T11-07-10.146Z-92bec361-0ca1-42f2-9729-7dca3a7eadb9.json",+ "winner": "attacker",+ "attacker": {+ "troops": 800,+ "survivors": 728,+ "losses": 0,+ "injured": 26,+ "lightly_injured": 46,+ "kills": 350+ },+ "defender": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 26+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 300,+ "survivors": 228,+ "losses": 0,+ "injured": 26,+ "lightly_injured": 46,+ "kills": 197+ },+ "marksman_t6": {+ "troops": 500,+ "survivors": 500,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 153+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 26+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 12,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/extra_damage_source_death_20260926/calibration_renee_gwen.json===================================================================--- testcases/emulator_verified/extra_damage_source_death_20260926/calibration_renee_gwen.json prev run+++ testcases/emulator_verified/extra_damage_source_death_20260926/calibration_renee_gwen.json this run@@ -0,0 +1,160 @@+[+ {+ "test_id": "calibration_renee_gwen",+ "description": "C2 battle report 2734693171388861",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 300,+ "marksman_t6": 500+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T11:09:12.000Z",+ "randomseed": 1790420953,+ "attacker": 743,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171388861",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T11-09-29.132Z-69c707d7-413f-41c5-9d0e-88030045e277.json",+ "winner": "attacker",+ "attacker": {+ "troops": 800,+ "survivors": 743,+ "losses": 0,+ "injured": 20,+ "lightly_injured": 37,+ "kills": 350+ },+ "defender": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 20+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 300,+ "survivors": 243,+ "losses": 0,+ "injured": 20,+ "lightly_injured": 37,+ "kills": 159+ },+ "marksman_t6": {+ "troops": 500,+ "survivors": 500,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 191+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 20+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 6,+ "displayed_kills": 6+ },+ "Blastmaster": {+ "triggered": 3,+ "displayed_kills": 2+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 9,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/extra_damage_source_death_20260926/gwen_r9_cancellation_control.json===================================================================--- testcases/emulator_verified/extra_damage_source_death_20260926/gwen_r9_cancellation_control.json prev run+++ testcases/emulator_verified/extra_damage_source_death_20260926/gwen_r9_cancellation_control.json this run@@ -0,0 +1,269 @@+[+ {+ "test_id": "gwen_r9_cancellation_control",+ "description": "C2 battle report 2734693171408557",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 3000,+ "marksman_t6": 53+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Hendrik": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 500,+ "marksman_t6": 750+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 479,+ "defense": 467.8,+ "lethality": 244.2,+ "health": 221.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T18:04:00.000Z",+ "randomseed": 1790445841,+ "attacker": 194,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171408557",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T18-04-17.244Z-8d12ef4c-be11-4b3b-b3c7-d530ced5dbb1.json",+ "winner": "attacker",+ "attacker": {+ "troops": 3053,+ "survivors": 194,+ "losses": 0,+ "injured": 1002,+ "lightly_injured": 1857,+ "kills": 438+ },+ "defender": {+ "troops": 1250,+ "survivors": 0,+ "losses": 0,+ "injured": 438,+ "lightly_injured": 812,+ "kills": 1002+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 3000,+ "survivors": 194,+ "losses": 0,+ "injured": 983,+ "lightly_injured": 1823,+ "kills": 419+ },+ "marksman_t6": {+ "troops": 53,+ "survivors": 0,+ "losses": 0,+ "injured": 19,+ "lightly_injured": 34,+ "kills": 19+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 28+ },+ "marksman_t6": {+ "troops": 750,+ "survivors": 0,+ "losses": 0,+ "injured": 263,+ "lightly_injured": 487,+ "kills": 974+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 24,+ "displayed_kills": 12+ },+ "Blastmaster": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 45,+ "displayed_kills": 88+ },+ "Armor of Barnacles": {+ "triggered": 33,+ "displayed_kills": null+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-26T18:04:45.000Z",+ "randomseed": 1790445886,+ "attacker": 194,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171408565",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T18-05-02.175Z-452ff48a-6dcc-40ca-8b00-9a5c36a98d5e.json",+ "winner": "attacker",+ "attacker": {+ "troops": 3053,+ "survivors": 194,+ "losses": 0,+ "injured": 1002,+ "lightly_injured": 1857,+ "kills": 438+ },+ "defender": {+ "troops": 1250,+ "survivors": 0,+ "losses": 0,+ "injured": 438,+ "lightly_injured": 812,+ "kills": 1002+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 3000,+ "survivors": 194,+ "losses": 0,+ "injured": 983,+ "lightly_injured": 1823,+ "kills": 419+ },+ "marksman_t6": {+ "troops": 53,+ "survivors": 0,+ "losses": 0,+ "injured": 19,+ "lightly_injured": 34,+ "kills": 19+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 28+ },+ "marksman_t6": {+ "troops": 750,+ "survivors": 0,+ "losses": 0,+ "injured": 263,+ "lightly_injured": 487,+ "kills": 974+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 24,+ "displayed_kills": 12+ },+ "Blastmaster": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 45,+ "displayed_kills": 88+ },+ "Armor of Barnacles": {+ "triggered": 33,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/extra_damage_source_death_20260926/gwen_r9_cancellation_death.json===================================================================--- testcases/emulator_verified/extra_damage_source_death_20260926/gwen_r9_cancellation_death.json prev run+++ testcases/emulator_verified/extra_damage_source_death_20260926/gwen_r9_cancellation_death.json this run@@ -0,0 +1,269 @@+[+ {+ "test_id": "gwen_r9_cancellation_death",+ "description": "C2 battle report 2734693171408434",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 3000,+ "marksman_t6": 52+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Hendrik": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 500,+ "marksman_t6": 750+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 479,+ "defense": 467.8,+ "lethality": 244.2,+ "health": 221.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T17:57:27.000Z",+ "randomseed": 1790445448,+ "attacker": 192,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171408434",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T17-57-45.229Z-2d7a73d1-1248-4d76-9a3a-0c69c963d44e.json",+ "winner": "attacker",+ "attacker": {+ "troops": 3052,+ "survivors": 192,+ "losses": 0,+ "injured": 1002,+ "lightly_injured": 1858,+ "kills": 438+ },+ "defender": {+ "troops": 1250,+ "survivors": 0,+ "losses": 0,+ "injured": 438,+ "lightly_injured": 812,+ "kills": 1002+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 3000,+ "survivors": 192,+ "losses": 0,+ "injured": 983,+ "lightly_injured": 1825,+ "kills": 420+ },+ "marksman_t6": {+ "troops": 52,+ "survivors": 0,+ "losses": 0,+ "injured": 19,+ "lightly_injured": 33,+ "kills": 18+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 29+ },+ "marksman_t6": {+ "troops": 750,+ "survivors": 0,+ "losses": 0,+ "injured": 263,+ "lightly_injured": 487,+ "kills": 973+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 23,+ "displayed_kills": 15+ },+ "Blastmaster": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 45,+ "displayed_kills": 87+ },+ "Armor of Barnacles": {+ "triggered": 33,+ "displayed_kills": null+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-26T17:58:13.000Z",+ "randomseed": 1790445494,+ "attacker": 192,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171408443",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T17-58-30.168Z-b0c109cf-6ebe-4725-a945-18cbeaf908ad.json",+ "winner": "attacker",+ "attacker": {+ "troops": 3052,+ "survivors": 192,+ "losses": 0,+ "injured": 1002,+ "lightly_injured": 1858,+ "kills": 438+ },+ "defender": {+ "troops": 1250,+ "survivors": 0,+ "losses": 0,+ "injured": 438,+ "lightly_injured": 812,+ "kills": 1002+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 3000,+ "survivors": 192,+ "losses": 0,+ "injured": 983,+ "lightly_injured": 1825,+ "kills": 420+ },+ "marksman_t6": {+ "troops": 52,+ "survivors": 0,+ "losses": 0,+ "injured": 19,+ "lightly_injured": 33,+ "kills": 18+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 29+ },+ "marksman_t6": {+ "troops": 750,+ "survivors": 0,+ "losses": 0,+ "injured": 263,+ "lightly_injured": 487,+ "kills": 973+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 23,+ "displayed_kills": 15+ },+ "Blastmaster": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 45,+ "displayed_kills": 87+ },+ "Armor of Barnacles": {+ "triggered": 33,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/extra_damage_source_death_20260926/gwen_r9_delayed_control.json===================================================================--- testcases/emulator_verified/extra_damage_source_death_20260926/gwen_r9_delayed_control.json prev run+++ testcases/emulator_verified/extra_damage_source_death_20260926/gwen_r9_delayed_control.json this run@@ -0,0 +1,269 @@+[+ {+ "test_id": "gwen_r9_delayed_control",+ "description": "C2 battle report 2734693171408658",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 3000,+ "marksman_t6": 31+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Hendrik": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 1000,+ "marksman_t6": 250+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 479,+ "defense": 467.8,+ "lethality": 244.2,+ "health": 221.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T18:11:36.000Z",+ "randomseed": 1790446297,+ "attacker": 369,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171408658",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T18-11-53.186Z-1b72cd00-24b4-4424-a041-5a8836f0c048.json",+ "winner": "attacker",+ "attacker": {+ "troops": 3031,+ "survivors": 369,+ "losses": 0,+ "injured": 932,+ "lightly_injured": 1730,+ "kills": 438+ },+ "defender": {+ "troops": 1250,+ "survivors": 0,+ "losses": 0,+ "injured": 438,+ "lightly_injured": 812,+ "kills": 932+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 3000,+ "survivors": 369,+ "losses": 0,+ "injured": 921,+ "lightly_injured": 1710,+ "kills": 423+ },+ "marksman_t6": {+ "troops": 31,+ "survivors": 0,+ "losses": 0,+ "injured": 11,+ "lightly_injured": 20,+ "kills": 15+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 98+ },+ "marksman_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 834+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 29,+ "displayed_kills": 16+ },+ "Blastmaster": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 55,+ "displayed_kills": 70+ },+ "Armor of Barnacles": {+ "triggered": 41,+ "displayed_kills": null+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-26T18:12:21.000Z",+ "randomseed": 1790446342,+ "attacker": 369,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171408672",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T18-12-38.205Z-ac7cba85-d246-44e2-beb3-fa15c0941d5c.json",+ "winner": "attacker",+ "attacker": {+ "troops": 3031,+ "survivors": 369,+ "losses": 0,+ "injured": 932,+ "lightly_injured": 1730,+ "kills": 438+ },+ "defender": {+ "troops": 1250,+ "survivors": 0,+ "losses": 0,+ "injured": 438,+ "lightly_injured": 812,+ "kills": 932+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 3000,+ "survivors": 369,+ "losses": 0,+ "injured": 921,+ "lightly_injured": 1710,+ "kills": 423+ },+ "marksman_t6": {+ "troops": 31,+ "survivors": 0,+ "losses": 0,+ "injured": 11,+ "lightly_injured": 20,+ "kills": 15+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 98+ },+ "marksman_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 834+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 29,+ "displayed_kills": 16+ },+ "Blastmaster": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 55,+ "displayed_kills": 70+ },+ "Armor of Barnacles": {+ "triggered": 41,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/extra_damage_source_death_20260926/gwen_r9_placement_control.json===================================================================--- testcases/emulator_verified/extra_damage_source_death_20260926/gwen_r9_placement_control.json prev run+++ testcases/emulator_verified/extra_damage_source_death_20260926/gwen_r9_placement_control.json this run@@ -0,0 +1,269 @@+[+ {+ "test_id": "gwen_r9_placement_control",+ "description": "C2 battle report 2734693171408610",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 2000,+ "marksman_t6": 24+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Hendrik": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 500,+ "marksman_t6": 250+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 479,+ "defense": 467.8,+ "lethality": 244.2,+ "health": 221.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T18:07:26.000Z",+ "randomseed": 1790446047,+ "attacker": 453,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171408610",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T18-07-43.221Z-5a0ad508-a114-4f33-8624-e0b1802ffb75.json",+ "winner": "attacker",+ "attacker": {+ "troops": 2024,+ "survivors": 453,+ "losses": 0,+ "injured": 551,+ "lightly_injured": 1020,+ "kills": 263+ },+ "defender": {+ "troops": 750,+ "survivors": 0,+ "losses": 0,+ "injured": 263,+ "lightly_injured": 487,+ "kills": 551+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 2000,+ "survivors": 453,+ "losses": 0,+ "injured": 542,+ "lightly_injured": 1005,+ "kills": 253+ },+ "marksman_t6": {+ "troops": 24,+ "survivors": 0,+ "losses": 0,+ "injured": 9,+ "lightly_injured": 15,+ "kills": 10+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 37+ },+ "marksman_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 514+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 24,+ "displayed_kills": 8+ },+ "Blastmaster": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 44,+ "displayed_kills": 47+ },+ "Armor of Barnacles": {+ "triggered": 33,+ "displayed_kills": null+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-26T18:08:11.000Z",+ "randomseed": 1790446092,+ "attacker": 453,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171408615",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T18-08-28.174Z-46a5e4b8-cee9-4395-bd6b-24f3eff69e20.json",+ "winner": "attacker",+ "attacker": {+ "troops": 2024,+ "survivors": 453,+ "losses": 0,+ "injured": 551,+ "lightly_injured": 1020,+ "kills": 263+ },+ "defender": {+ "troops": 750,+ "survivors": 0,+ "losses": 0,+ "injured": 263,+ "lightly_injured": 487,+ "kills": 551+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 2000,+ "survivors": 453,+ "losses": 0,+ "injured": 542,+ "lightly_injured": 1005,+ "kills": 253+ },+ "marksman_t6": {+ "troops": 24,+ "survivors": 0,+ "losses": 0,+ "injured": 9,+ "lightly_injured": 15,+ "kills": 10+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 37+ },+ "marksman_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 514+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 24,+ "displayed_kills": 8+ },+ "Blastmaster": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 44,+ "displayed_kills": 47+ },+ "Armor of Barnacles": {+ "triggered": 33,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/extra_damage_source_death_20260926/gwen_r9_placement_death.json===================================================================--- testcases/emulator_verified/extra_damage_source_death_20260926/gwen_r9_placement_death.json prev run+++ testcases/emulator_verified/extra_damage_source_death_20260926/gwen_r9_placement_death.json this run@@ -0,0 +1,269 @@+[+ {+ "test_id": "gwen_r9_placement_death",+ "description": "C2 battle report 2734693171408572",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 2000,+ "marksman_t6": 23+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Hendrik": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 500,+ "marksman_t6": 250+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 479,+ "defense": 467.8,+ "lethality": 244.2,+ "health": 221.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T18:05:30.000Z",+ "randomseed": 1790445931,+ "attacker": 436,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171408572",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T18-05-47.242Z-81786722-7074-4ce9-8629-d810983a753a.json",+ "winner": "attacker",+ "attacker": {+ "troops": 2023,+ "survivors": 436,+ "losses": 0,+ "injured": 557,+ "lightly_injured": 1030,+ "kills": 263+ },+ "defender": {+ "troops": 750,+ "survivors": 0,+ "losses": 0,+ "injured": 263,+ "lightly_injured": 487,+ "kills": 557+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 2000,+ "survivors": 436,+ "losses": 0,+ "injured": 548,+ "lightly_injured": 1016,+ "kills": 253+ },+ "marksman_t6": {+ "troops": 23,+ "survivors": 0,+ "losses": 0,+ "injured": 9,+ "lightly_injured": 14,+ "kills": 10+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 39+ },+ "marksman_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 518+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 23,+ "displayed_kills": 8+ },+ "Blastmaster": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 45,+ "displayed_kills": 44+ },+ "Armor of Barnacles": {+ "triggered": 33,+ "displayed_kills": null+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-26T18:06:15.000Z",+ "randomseed": 1790445976,+ "attacker": 436,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171408590",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T18-06-32.177Z-b729f1ef-3778-4b31-9e3a-dd3abaa17e8a.json",+ "winner": "attacker",+ "attacker": {+ "troops": 2023,+ "survivors": 436,+ "losses": 0,+ "injured": 557,+ "lightly_injured": 1030,+ "kills": 263+ },+ "defender": {+ "troops": 750,+ "survivors": 0,+ "losses": 0,+ "injured": 263,+ "lightly_injured": 487,+ "kills": 557+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 2000,+ "survivors": 436,+ "losses": 0,+ "injured": 548,+ "lightly_injured": 1016,+ "kills": 253+ },+ "marksman_t6": {+ "troops": 23,+ "survivors": 0,+ "losses": 0,+ "injured": 9,+ "lightly_injured": 14,+ "kills": 10+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 39+ },+ "marksman_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 518+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 23,+ "displayed_kills": 8+ },+ "Blastmaster": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 45,+ "displayed_kills": 44+ },+ "Armor of Barnacles": {+ "triggered": 33,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/extra_damage_source_death_20260926/renee_gwen_source_death.json===================================================================--- testcases/emulator_verified/extra_damage_source_death_20260926/renee_gwen_source_death.json prev run+++ testcases/emulator_verified/extra_damage_source_death_20260926/renee_gwen_source_death.json this run@@ -0,0 +1,241 @@+[+ {+ "test_id": "renee_gwen_source_death",+ "description": "C2 battle report 2734693171408478",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 79,+ "marksman_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 3000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T18:00:38.000Z",+ "randomseed": 1790445639,+ "attacker": 0,+ "defender": 12,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171408478",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T18-00-55.184Z-1b0aaf6e-b0f8-4058-a813-1b69f2d3c66e.json",+ "winner": "defender",+ "attacker": {+ "troops": 1079,+ "survivors": 0,+ "losses": 0,+ "injured": 378,+ "lightly_injured": 701,+ "kills": 1046+ },+ "defender": {+ "troops": 3000,+ "survivors": 12,+ "losses": 0,+ "injured": 1046,+ "lightly_injured": 1942,+ "kills": 378+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 79,+ "survivors": 0,+ "losses": 0,+ "injured": 28,+ "lightly_injured": 51,+ "kills": 27+ },+ "marksman_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 1019+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 3000,+ "survivors": 12,+ "losses": 0,+ "injured": 1046,+ "lightly_injured": 1942,+ "kills": 378+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 27,+ "displayed_kills": 31+ },+ "Blastmaster": {+ "triggered": 32,+ "displayed_kills": 19+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 80,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-26T18:01:23.000Z",+ "randomseed": 1790445684,+ "attacker": 0,+ "defender": 12,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171408507",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T18-01-40.204Z-654b3470-11f7-49f1-9488-2f44c690cf4c.json",+ "winner": "defender",+ "attacker": {+ "troops": 1079,+ "survivors": 0,+ "losses": 0,+ "injured": 378,+ "lightly_injured": 701,+ "kills": 1046+ },+ "defender": {+ "troops": 3000,+ "survivors": 12,+ "losses": 0,+ "injured": 1046,+ "lightly_injured": 1942,+ "kills": 378+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 79,+ "survivors": 0,+ "losses": 0,+ "injured": 28,+ "lightly_injured": 51,+ "kills": 27+ },+ "marksman_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 1019+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 3000,+ "survivors": 12,+ "losses": 0,+ "injured": 1046,+ "lightly_injured": 1942,+ "kills": 378+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 27,+ "displayed_kills": 31+ },+ "Blastmaster": {+ "triggered": 32,+ "displayed_kills": 19+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 80,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/extra_damage_source_death_20260926/renee_gwen_survival_control.json===================================================================--- testcases/emulator_verified/extra_damage_source_death_20260926/renee_gwen_survival_control.json prev run+++ testcases/emulator_verified/extra_damage_source_death_20260926/renee_gwen_survival_control.json this run@@ -0,0 +1,241 @@+[+ {+ "test_id": "renee_gwen_survival_control",+ "description": "C2 battle report 2734693171408520",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 84,+ "marksman_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 3000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T18:02:15.000Z",+ "randomseed": 1790445736,+ "attacker": 90,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171408520",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T18-02-32.179Z-c2d3a7db-9772-4c67-8d3b-f9c0cb18ab5c.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1084,+ "survivors": 90,+ "losses": 0,+ "injured": 349,+ "lightly_injured": 645,+ "kills": 1050+ },+ "defender": {+ "troops": 3000,+ "survivors": 0,+ "losses": 0,+ "injured": 1050,+ "lightly_injured": 1950,+ "kills": 349+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 84,+ "survivors": 0,+ "losses": 0,+ "injured": 30,+ "lightly_injured": 54,+ "kills": 29+ },+ "marksman_t6": {+ "troops": 1000,+ "survivors": 90,+ "losses": 0,+ "injured": 319,+ "lightly_injured": 591,+ "kills": 1021+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 3000,+ "survivors": 0,+ "losses": 0,+ "injured": 1050,+ "lightly_injured": 1950,+ "kills": 349+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 23,+ "displayed_kills": 30+ },+ "Blastmaster": {+ "triggered": 27,+ "displayed_kills": 18+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 68,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-26T18:03:00.000Z",+ "randomseed": 1790445781,+ "attacker": 90,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171408548",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T18-03-17.244Z-e2676e3e-a9d2-4ef2-83c5-1ed62d12c84a.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1084,+ "survivors": 90,+ "losses": 0,+ "injured": 349,+ "lightly_injured": 645,+ "kills": 1050+ },+ "defender": {+ "troops": 3000,+ "survivors": 0,+ "losses": 0,+ "injured": 1050,+ "lightly_injured": 1950,+ "kills": 349+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 84,+ "survivors": 0,+ "losses": 0,+ "injured": 30,+ "lightly_injured": 54,+ "kills": 29+ },+ "marksman_t6": {+ "troops": 1000,+ "survivors": 90,+ "losses": 0,+ "injured": 319,+ "lightly_injured": 591,+ "kills": 1021+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 3000,+ "survivors": 0,+ "losses": 0,+ "injured": 1050,+ "lightly_injured": 1950,+ "kills": 349+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 23,+ "displayed_kills": 30+ },+ "Blastmaster": {+ "triggered": 27,+ "displayed_kills": 18+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 68,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/extra_damage_source_death_20260926/renee_source_death.json===================================================================--- testcases/emulator_verified/extra_damage_source_death_20260926/renee_source_death.json prev run+++ testcases/emulator_verified/extra_damage_source_death_20260926/renee_source_death.json this run@@ -0,0 +1,215 @@+[+ {+ "test_id": "renee_source_death",+ "description": "C2 battle report 2734693171388980",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 62,+ "marksman_t6": 800+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 1500+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T11:13:33.000Z",+ "randomseed": 1790421214,+ "attacker": 10,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171388980",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T11-13-50.165Z-8253a420-20d4-426c-904c-10ab499e9377.json",+ "winner": "attacker",+ "attacker": {+ "troops": 862,+ "survivors": 10,+ "losses": 0,+ "injured": 299,+ "lightly_injured": 553,+ "kills": 525+ },+ "defender": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 299+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 62,+ "survivors": 0,+ "losses": 0,+ "injured": 22,+ "lightly_injured": 40,+ "kills": 25+ },+ "marksman_t6": {+ "troops": 800,+ "survivors": 10,+ "losses": 0,+ "injured": 277,+ "lightly_injured": 513,+ "kills": 500+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 299+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 75,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-26T11:14:18.000Z",+ "randomseed": 1790421259,+ "attacker": 10,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171389013",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T11-14-35.129Z-d0a853a7-47fb-4ef1-a47a-a500d7761e9d.json",+ "winner": "attacker",+ "attacker": {+ "troops": 862,+ "survivors": 10,+ "losses": 0,+ "injured": 299,+ "lightly_injured": 553,+ "kills": 525+ },+ "defender": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 299+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 62,+ "survivors": 0,+ "losses": 0,+ "injured": 22,+ "lightly_injured": 40,+ "kills": 25+ },+ "marksman_t6": {+ "troops": 800,+ "survivors": 10,+ "losses": 0,+ "injured": 277,+ "lightly_injured": 513,+ "kills": 500+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 299+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 75,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/extra_damage_source_death_20260926/renee_survival_control.json===================================================================--- testcases/emulator_verified/extra_damage_source_death_20260926/renee_survival_control.json prev run+++ testcases/emulator_verified/extra_damage_source_death_20260926/renee_survival_control.json this run@@ -0,0 +1,215 @@+[+ {+ "test_id": "renee_survival_control",+ "description": "C2 battle report 2734693171408415",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 63,+ "marksman_t6": 800+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 1500+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T17:56:15.000Z",+ "randomseed": 1790445376,+ "attacker": 69,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171408415",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T17-56-32.185Z-2cdd3111-ec54-4bd3-bf41-0526b5b4e05a.json",+ "winner": "attacker",+ "attacker": {+ "troops": 863,+ "survivors": 69,+ "losses": 0,+ "injured": 279,+ "lightly_injured": 515,+ "kills": 525+ },+ "defender": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 279+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 63,+ "survivors": 0,+ "losses": 0,+ "injured": 23,+ "lightly_injured": 40,+ "kills": 27+ },+ "marksman_t6": {+ "troops": 800,+ "survivors": 69,+ "losses": 0,+ "injured": 256,+ "lightly_injured": 475,+ "kills": 498+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 279+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 66,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-26T17:57:00.000Z",+ "randomseed": 1790445421,+ "attacker": 69,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171408426",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T17-57-17.242Z-9d99cbcc-5df0-4e76-adfe-0c3e6ae3120f.json",+ "winner": "attacker",+ "attacker": {+ "troops": 863,+ "survivors": 69,+ "losses": 0,+ "injured": 279,+ "lightly_injured": 515,+ "kills": 525+ },+ "defender": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 279+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 63,+ "survivors": 0,+ "losses": 0,+ "injured": 23,+ "lightly_injured": 40,+ "kills": 27+ },+ "marksman_t6": {+ "troops": 800,+ "survivors": 69,+ "losses": 0,+ "injured": 256,+ "lightly_injured": 475,+ "kills": 498+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 279+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 66,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gatot_fresh_20260925/gatot_mixed_gordon_gwen.json===================================================================--- testcases/emulator_verified/gatot_fresh_20260925/gatot_mixed_gordon_gwen.json prev run+++ testcases/emulator_verified/gatot_fresh_20260925/gatot_mixed_gordon_gwen.json this run@@ -0,0 +1,235 @@+[+ {+ "test_id": "gatot_mixed_gordon_gwen",+ "description": "C2 battle report 2734693171351221",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 2,+ "skill_4": 0+ },+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 315,+ "lancer_t6": 353,+ "marksman_t6": 204+ },+ "stats": {+ "infantry": {+ "attack": 513.98,+ "defense": 496.98,+ "lethality": 250.71,+ "health": 274.79+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Jessie": {+ "skill_1": 1,+ "skill_2": 1+ },+ "Hendrik": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 270,+ "lancer_t6": 350,+ "marksman_t6": 243+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 297.72,+ "defense": 297.02,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 479,+ "defense": 467.8,+ "lethality": 244.2,+ "health": 221.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T13:25:56.000Z",+ "randomseed": 1790342757,+ "attacker": 0,+ "defender": 593,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171351221",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T13-26-12.142Z-057d5450-6a59-42f8-b6ed-5f8d74d49fad.json",+ "winner": "defender",+ "attacker": {+ "troops": 872,+ "survivors": 0,+ "losses": 0,+ "injured": 307,+ "lightly_injured": 565,+ "kills": 96+ },+ "defender": {+ "troops": 863,+ "survivors": 593,+ "losses": 0,+ "injured": 96,+ "lightly_injured": 174,+ "kills": 307+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 315,+ "survivors": 0,+ "losses": 0,+ "injured": 111,+ "lightly_injured": 204,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 353,+ "survivors": 0,+ "losses": 0,+ "injured": 124,+ "lightly_injured": 229,+ "kills": 36+ },+ "marksman_t6": {+ "troops": 204,+ "survivors": 0,+ "losses": 0,+ "injured": 72,+ "lightly_injured": 132,+ "kills": 60+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 270,+ "survivors": 33,+ "losses": 0,+ "injured": 83,+ "lightly_injured": 154,+ "kills": 28+ },+ "lancer_t6": {+ "troops": 350,+ "survivors": 332,+ "losses": 0,+ "injured": 7,+ "lightly_injured": 11,+ "kills": 78+ },+ "marksman_t6": {+ "troops": 243,+ "survivors": 228,+ "losses": 0,+ "injured": 6,+ "lightly_injured": 9,+ "kills": 201+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 18,+ "displayed_kills": 3+ },+ "Blastmaster": {+ "triggered": 8,+ "displayed_kills": 12+ }+ },+ "Gordon": {+ "Toxic Release": {+ "triggered": 10,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 20,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 14,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 14,+ "displayed_kills": 61+ },+ "Armor of Barnacles": {+ "triggered": 10,+ "displayed_kills": null+ }+ },+ "Gatot": {+ "King's Bestowal": {+ "triggered": 43,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gatot_fresh_20260925/gatot_mixed_without_gordon.json===================================================================--- testcases/emulator_verified/gatot_fresh_20260925/gatot_mixed_without_gordon.json prev run+++ testcases/emulator_verified/gatot_fresh_20260925/gatot_mixed_without_gordon.json this run@@ -0,0 +1,215 @@+[+ {+ "test_id": "gatot_mixed_without_gordon",+ "description": "C2 battle report 2734693171351259",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 2,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 315,+ "lancer_t6": 353,+ "marksman_t6": 204+ },+ "stats": {+ "infantry": {+ "attack": 513.98,+ "defense": 496.98,+ "lethality": 250.71,+ "health": 274.79+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Jessie": {+ "skill_1": 1,+ "skill_2": 1+ },+ "Hendrik": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 270,+ "lancer_t6": 350,+ "marksman_t6": 243+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 297.72,+ "defense": 297.02,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 479,+ "defense": 467.8,+ "lethality": 244.2,+ "health": 221.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T13:27:28.000Z",+ "randomseed": 1790342849,+ "attacker": 0,+ "defender": 726,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171351259",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T13-27-44.130Z-a2aec42e-5a43-4aee-b690-4d22d33ceb83.json",+ "winner": "defender",+ "attacker": {+ "troops": 872,+ "survivors": 0,+ "losses": 0,+ "injured": 307,+ "lightly_injured": 565,+ "kills": 49+ },+ "defender": {+ "troops": 863,+ "survivors": 726,+ "losses": 0,+ "injured": 49,+ "lightly_injured": 88,+ "kills": 307+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 315,+ "survivors": 0,+ "losses": 0,+ "injured": 111,+ "lightly_injured": 204,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 353,+ "survivors": 0,+ "losses": 0,+ "injured": 124,+ "lightly_injured": 229,+ "kills": 6+ },+ "marksman_t6": {+ "troops": 204,+ "survivors": 0,+ "losses": 0,+ "injured": 72,+ "lightly_injured": 132,+ "kills": 43+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 270,+ "survivors": 162,+ "losses": 0,+ "injured": 38,+ "lightly_injured": 70,+ "kills": 37+ },+ "lancer_t6": {+ "troops": 350,+ "survivors": 334,+ "losses": 0,+ "injured": 6,+ "lightly_injured": 10,+ "kills": 69+ },+ "marksman_t6": {+ "troops": 243,+ "survivors": 230,+ "losses": 0,+ "injured": 5,+ "lightly_injured": 8,+ "kills": 201+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 15,+ "displayed_kills": 1+ },+ "Blastmaster": {+ "triggered": 7,+ "displayed_kills": 11+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 12,+ "displayed_kills": 71+ },+ "Armor of Barnacles": {+ "triggered": 9,+ "displayed_kills": null+ }+ },+ "Gatot": {+ "King's Bestowal": {+ "triggered": 36,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gatot_fresh_20260925/gatot_mixed_without_gwen.json===================================================================--- testcases/emulator_verified/gatot_fresh_20260925/gatot_mixed_without_gwen.json prev run+++ testcases/emulator_verified/gatot_fresh_20260925/gatot_mixed_without_gwen.json this run@@ -0,0 +1,219 @@+[+ {+ "test_id": "gatot_mixed_without_gwen",+ "description": "C2 battle report 2734693171351287",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Wu Ming": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 2,+ "skill_4": 0+ },+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 315,+ "lancer_t6": 353,+ "marksman_t6": 204+ },+ "stats": {+ "infantry": {+ "attack": 513.98,+ "defense": 496.98,+ "lethality": 250.71,+ "health": 274.79+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Jessie": {+ "skill_1": 1,+ "skill_2": 1+ },+ "Hendrik": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 270,+ "lancer_t6": 350,+ "marksman_t6": 243+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 297.72,+ "defense": 297.02,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 479,+ "defense": 467.8,+ "lethality": 244.2,+ "health": 221.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T13:29:36.000Z",+ "randomseed": 1790342977,+ "attacker": 0,+ "defender": 722,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171351287",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T13-29-52.137Z-fc0b1017-6ca0-4480-bb39-39c494903c90.json",+ "winner": "defender",+ "attacker": {+ "troops": 872,+ "survivors": 0,+ "losses": 0,+ "injured": 307,+ "lightly_injured": 565,+ "kills": 50+ },+ "defender": {+ "troops": 863,+ "survivors": 722,+ "losses": 0,+ "injured": 50,+ "lightly_injured": 91,+ "kills": 307+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 315,+ "survivors": 0,+ "losses": 0,+ "injured": 111,+ "lightly_injured": 204,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 353,+ "survivors": 0,+ "losses": 0,+ "injured": 124,+ "lightly_injured": 229,+ "kills": 22+ },+ "marksman_t6": {+ "troops": 204,+ "survivors": 0,+ "losses": 0,+ "injured": 72,+ "lightly_injured": 132,+ "kills": 28+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 270,+ "survivors": 129,+ "losses": 0,+ "injured": 50,+ "lightly_injured": 91,+ "kills": 33+ },+ "lancer_t6": {+ "troops": 350,+ "survivors": 350,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 70+ },+ "marksman_t6": {+ "troops": 243,+ "survivors": 243,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 204+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": 9,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 19,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 13,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 13,+ "displayed_kills": 71+ },+ "Armor of Barnacles": {+ "triggered": 9,+ "displayed_kills": null+ }+ },+ "Gatot": {+ "King's Bestowal": {+ "triggered": 39,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gordon_gwen_t9_probe_20260929/gg_1000i_1000l_vs_20000t9.json===================================================================--- testcases/emulator_verified/gordon_gwen_t9_probe_20260929/gg_1000i_1000l_vs_20000t9.json prev run+++ testcases/emulator_verified/gordon_gwen_t9_probe_20260929/gg_1000i_1000l_vs_20000t9.json this run@@ -0,0 +1,175 @@+[+ {+ "test_id": "gg_1000i_1000l_vs_20000t9",+ "description": "C2 battle report 2734693171529413",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 1000,+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 20000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T13:22:28.000Z",+ "randomseed": 1790688149,+ "attacker": 0,+ "defender": 17781,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171529413",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T13-22-44.129Z-2e389ab6-7179-425b-a340-ca62e18cec4f.json",+ "winner": "defender",+ "attacker": {+ "troops": 2000,+ "survivors": 0,+ "losses": 0,+ "injured": 700,+ "lightly_injured": 1300,+ "kills": 777+ },+ "defender": {+ "troops": 20000,+ "survivors": 17781,+ "losses": 0,+ "injured": 777,+ "lightly_injured": 1442,+ "kills": 700+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 77+ },+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 700+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 20000,+ "survivors": 17781,+ "losses": 0,+ "injured": 777,+ "lightly_injured": 1442,+ "kills": 700+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 6,+ "displayed_kills": 25+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Gordon": {+ "Toxic Release": {+ "triggered": 6,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 12,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 8,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 5,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gordon_gwen_t9_probe_20260929/gg_1000l_vs_20000t9.json===================================================================--- testcases/emulator_verified/gordon_gwen_t9_probe_20260929/gg_1000l_vs_20000t9.json prev run+++ testcases/emulator_verified/gordon_gwen_t9_probe_20260929/gg_1000l_vs_20000t9.json this run@@ -0,0 +1,166 @@+[+ {+ "test_id": "gg_1000l_vs_20000t9",+ "description": "C2 battle report 2734693171525958",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 20000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T10:32:35.000Z",+ "randomseed": 1790677956,+ "attacker": 0,+ "defender": 19522,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171525958",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T10-32-51.116Z-d76be9d4-fc03-4b9e-bd02-43afbb6cde0e.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 168+ },+ "defender": {+ "troops": 20000,+ "survivors": 19522,+ "losses": 0,+ "injured": 168,+ "lightly_injured": 310,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 168+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 20000,+ "survivors": 19522,+ "losses": 0,+ "injured": 168,+ "lightly_injured": 310,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 1,+ "displayed_kills": 3+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Gordon": {+ "Toxic Release": {+ "triggered": 2,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 5,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 3,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gordon_gwen_t9_probe_20260929/gg_1000l_vs_20000t9l_10000t9m.json===================================================================--- testcases/emulator_verified/gordon_gwen_t9_probe_20260929/gg_1000l_vs_20000t9l_10000t9m.json prev run+++ testcases/emulator_verified/gordon_gwen_t9_probe_20260929/gg_1000l_vs_20000t9l_10000t9m.json this run@@ -0,0 +1,179 @@+[+ {+ "test_id": "gg_1000l_vs_20000t9l_10000t9m",+ "description": "C2 battle report 2734693171526025",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 20000,+ "marksman_t9": 10000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T10:39:37.000Z",+ "randomseed": 1790678378,+ "attacker": 0,+ "defender": 29802,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171526025",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T10-39-53.124Z-16f3243d-fcfc-4721-b36d-a24f5a7b90d0.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 70+ },+ "defender": {+ "troops": 30000,+ "survivors": 29802,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 128,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 70+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 20000,+ "survivors": 19802,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 128,+ "kills": 168+ },+ "marksman_t9": {+ "troops": 10000,+ "survivors": 10000,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 182+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": null,+ "displayed_kills": null+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Gordon": {+ "Toxic Release": {+ "triggered": 1,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 2,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 4,+ "displayed_kills": null+ },+ "Volley": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gordon_gwen_t9_probe_20260929/gg_60i_1000l_vs_20000t9.json===================================================================--- testcases/emulator_verified/gordon_gwen_t9_probe_20260929/gg_60i_1000l_vs_20000t9.json prev run+++ testcases/emulator_verified/gordon_gwen_t9_probe_20260929/gg_60i_1000l_vs_20000t9.json this run@@ -0,0 +1,175 @@+[+ {+ "test_id": "gg_60i_1000l_vs_20000t9",+ "description": "C2 battle report 2734693171525976",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 60,+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 20000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T10:34:07.000Z",+ "randomseed": 1790678048,+ "attacker": 0,+ "defender": 19352,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171525976",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T10-34-23.127Z-cf5d2472-b91f-43ec-a71a-adc75c5e37db.json",+ "winner": "defender",+ "attacker": {+ "troops": 1060,+ "survivors": 0,+ "losses": 0,+ "injured": 371,+ "lightly_injured": 689,+ "kills": 227+ },+ "defender": {+ "troops": 20000,+ "survivors": 19352,+ "losses": 0,+ "injured": 227,+ "lightly_injured": 421,+ "kills": 371+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 60,+ "survivors": 0,+ "losses": 0,+ "injured": 21,+ "lightly_injured": 39,+ "kills": 1+ },+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 226+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 20000,+ "survivors": 19352,+ "losses": 0,+ "injured": 227,+ "lightly_injured": 421,+ "kills": 371+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 2,+ "displayed_kills": 6+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Gordon": {+ "Toxic Release": {+ "triggered": 3,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 6,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 4,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gordon_gwen_t9_probe_20260929/gg_700i_1000l_vs_20000t9.json===================================================================--- testcases/emulator_verified/gordon_gwen_t9_probe_20260929/gg_700i_1000l_vs_20000t9.json prev run+++ testcases/emulator_verified/gordon_gwen_t9_probe_20260929/gg_700i_1000l_vs_20000t9.json this run@@ -0,0 +1,175 @@+[+ {+ "test_id": "gg_700i_1000l_vs_20000t9",+ "description": "C2 battle report 2734693171529402",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 700,+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 20000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T13:21:42.000Z",+ "randomseed": 1790688103,+ "attacker": 0,+ "defender": 18333,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171529402",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T13-21-58.135Z-bff61946-725a-40ca-b8b5-a8024749d8ac.json",+ "winner": "defender",+ "attacker": {+ "troops": 1700,+ "survivors": 0,+ "losses": 0,+ "injured": 595,+ "lightly_injured": 1105,+ "kills": 584+ },+ "defender": {+ "troops": 20000,+ "survivors": 18333,+ "losses": 0,+ "injured": 584,+ "lightly_injured": 1083,+ "kills": 595+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 700,+ "survivors": 0,+ "losses": 0,+ "injured": 245,+ "lightly_injured": 455,+ "kills": 43+ },+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 541+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 20000,+ "survivors": 18333,+ "losses": 0,+ "injured": 584,+ "lightly_injured": 1083,+ "kills": 595+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 5,+ "displayed_kills": 18+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Gordon": {+ "Toxic Release": {+ "triggered": 5,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 10,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 7,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gordon_gwen_t9_probe_20260929/go_1000l_vs_20000t9.json===================================================================--- testcases/emulator_verified/gordon_gwen_t9_probe_20260929/go_1000l_vs_20000t9.json prev run+++ testcases/emulator_verified/gordon_gwen_t9_probe_20260929/go_1000l_vs_20000t9.json this run@@ -0,0 +1,150 @@+[+ {+ "test_id": "go_1000l_vs_20000t9",+ "description": "C2 battle report 2734693171525960",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 20000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T10:33:21.000Z",+ "randomseed": 1790678002,+ "attacker": 0,+ "defender": 19586,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171525960",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T10-33-37.111Z-abf53af6-2526-4ff0-b10e-eecbf5b1c1d4.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 145+ },+ "defender": {+ "troops": 20000,+ "survivors": 19586,+ "losses": 0,+ "injured": 145,+ "lightly_injured": 269,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 145+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 20000,+ "survivors": 19586,+ "losses": 0,+ "injured": 145,+ "lightly_injured": 269,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": 2,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 5,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 3,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gordon_gwen_t9_probe_20260929/go_1000l_vs_20000t9l_10000t9m.json===================================================================--- testcases/emulator_verified/gordon_gwen_t9_probe_20260929/go_1000l_vs_20000t9l_10000t9m.json prev run+++ testcases/emulator_verified/gordon_gwen_t9_probe_20260929/go_1000l_vs_20000t9l_10000t9m.json this run@@ -0,0 +1,163 @@+[+ {+ "test_id": "go_1000l_vs_20000t9l_10000t9m",+ "description": "C2 battle report 2734693171526029",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 20000,+ "marksman_t9": 10000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T10:40:22.000Z",+ "randomseed": 1790678423,+ "attacker": 0,+ "defender": 29805,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171526029",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T10-40-38.118Z-3fb7285e-018f-4026-8607-f7834e4fbac2.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 69+ },+ "defender": {+ "troops": 30000,+ "survivors": 29805,+ "losses": 0,+ "injured": 69,+ "lightly_injured": 126,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 69+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 20000,+ "survivors": 19805,+ "losses": 0,+ "injured": 69,+ "lightly_injured": 126,+ "kills": 168+ },+ "marksman_t9": {+ "troops": 10000,+ "survivors": 10000,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 182+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": 1,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 2,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 2,+ "displayed_kills": null+ },+ "Volley": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gordon_gwen_t9_probe_20260929/go_60i_1000l_vs_20000t9.json===================================================================--- testcases/emulator_verified/gordon_gwen_t9_probe_20260929/go_60i_1000l_vs_20000t9.json prev run+++ testcases/emulator_verified/gordon_gwen_t9_probe_20260929/go_60i_1000l_vs_20000t9.json this run@@ -0,0 +1,159 @@+[+ {+ "test_id": "go_60i_1000l_vs_20000t9",+ "description": "C2 battle report 2734693171525981",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 60,+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 20000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T10:34:53.000Z",+ "randomseed": 1790678094,+ "attacker": 0,+ "defender": 19449,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171525981",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T10-35-09.110Z-573bbf53-ec59-495d-9d00-4a32c5eca9c6.json",+ "winner": "defender",+ "attacker": {+ "troops": 1060,+ "survivors": 0,+ "losses": 0,+ "injured": 371,+ "lightly_injured": 689,+ "kills": 193+ },+ "defender": {+ "troops": 20000,+ "survivors": 19449,+ "losses": 0,+ "injured": 193,+ "lightly_injured": 358,+ "kills": 371+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 60,+ "survivors": 0,+ "losses": 0,+ "injured": 21,+ "lightly_injured": 39,+ "kills": 1+ },+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 192+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 20000,+ "survivors": 19449,+ "losses": 0,+ "injured": 193,+ "lightly_injured": 358,+ "kills": 371+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": 3,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 6,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 4,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 3,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_renee_fresh_20260926/wip_1000l_1m_vs_3500l.json===================================================================--- testcases/emulator_verified/gwen_renee_fresh_20260926/wip_1000l_1m_vs_3500l.json prev run+++ testcases/emulator_verified/gwen_renee_fresh_20260926/wip_1000l_1m_vs_3500l.json this run@@ -0,0 +1,155 @@+[+ {+ "test_id": "wip_1000l_1m_vs_3500l",+ "description": "C2 battle report 2734693171371399",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000,+ "marksman_t6": 1+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 3500+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T00:56:32.000Z",+ "randomseed": 1790384193,+ "attacker": 0,+ "defender": 545,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171371399",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T00-57-00.243Z-11817d8c-b1ca-4dd8-9ece-dc6e05e7a552.json",+ "winner": "defender",+ "attacker": {+ "troops": 1001,+ "survivors": 0,+ "losses": 0,+ "injured": 351,+ "lightly_injured": 650,+ "kills": 1035+ },+ "defender": {+ "troops": 3500,+ "survivors": 545,+ "losses": 0,+ "injured": 1035,+ "lightly_injured": 1920,+ "kills": 351+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 999+ },+ "marksman_t6": {+ "troops": 1,+ "survivors": 0,+ "losses": 0,+ "injured": 1,+ "lightly_injured": 0,+ "kills": 36+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 3500,+ "survivors": 545,+ "losses": 0,+ "injured": 1035,+ "lightly_injured": 1920,+ "kills": 351+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 14,+ "displayed_kills": 14+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 21,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_renee_fresh_20260926/wip_1000l_vs_3500l.json===================================================================--- testcases/emulator_verified/gwen_renee_fresh_20260926/wip_1000l_vs_3500l.json prev run+++ testcases/emulator_verified/gwen_renee_fresh_20260926/wip_1000l_vs_3500l.json this run@@ -0,0 +1,146 @@+[+ {+ "test_id": "wip_1000l_vs_3500l",+ "description": "C2 battle report 2734693171371279",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 3500+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T00:53:51.000Z",+ "randomseed": 1790384032,+ "attacker": 0,+ "defender": 654,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171371279",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T00-54-19.178Z-707d1072-d904-43c8-85ad-61ffa7f296bb.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 997+ },+ "defender": {+ "troops": 3500,+ "survivors": 654,+ "losses": 0,+ "injured": 997,+ "lightly_injured": 1849,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 997+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 3500,+ "survivors": 654,+ "losses": 0,+ "injured": 997,+ "lightly_injured": 1849,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 6,+ "displayed_kills": 13+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 20,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_renee_fresh_20260926/wip_4000l_vs_300l.json===================================================================--- testcases/emulator_verified/gwen_renee_fresh_20260926/wip_4000l_vs_300l.json prev run+++ testcases/emulator_verified/gwen_renee_fresh_20260926/wip_4000l_vs_300l.json this run@@ -0,0 +1,146 @@+[+ {+ "test_id": "wip_4000l_vs_300l",+ "description": "C2 battle report 2734693171370798",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 4000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T00:42:04.000Z",+ "randomseed": 1790383325,+ "attacker": 3985,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171370798",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T00-42-32.138Z-b0d7db90-2e1c-4b93-866c-66a96d7c38b6.json",+ "winner": "attacker",+ "attacker": {+ "troops": 4000,+ "survivors": 3985,+ "losses": 0,+ "injured": 6,+ "lightly_injured": 9,+ "kills": 105+ },+ "defender": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 6+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 4000,+ "survivors": 3985,+ "losses": 0,+ "injured": 6,+ "lightly_injured": 9,+ "kills": 105+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 6+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_renee_fresh_20260926/wip_4000l_vs_400l.json===================================================================--- testcases/emulator_verified/gwen_renee_fresh_20260926/wip_4000l_vs_400l.json prev run+++ testcases/emulator_verified/gwen_renee_fresh_20260926/wip_4000l_vs_400l.json this run@@ -0,0 +1,146 @@+[+ {+ "test_id": "wip_4000l_vs_400l",+ "description": "C2 battle report 2734693171370827",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 4000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 400+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T00:43:47.000Z",+ "randomseed": 1790383428,+ "attacker": 3977,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171370827",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T00-44-15.152Z-6f0cd098-d02a-4642-b2e5-6de860cc40e6.json",+ "winner": "attacker",+ "attacker": {+ "troops": 4000,+ "survivors": 3977,+ "losses": 0,+ "injured": 9,+ "lightly_injured": 14,+ "kills": 140+ },+ "defender": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 9+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 4000,+ "survivors": 3977,+ "losses": 0,+ "injured": 9,+ "lightly_injured": 14,+ "kills": 140+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 9+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_renee_fresh_20260926/wip_4000l_vs_600l.json===================================================================--- testcases/emulator_verified/gwen_renee_fresh_20260926/wip_4000l_vs_600l.json prev run+++ testcases/emulator_verified/gwen_renee_fresh_20260926/wip_4000l_vs_600l.json this run@@ -0,0 +1,146 @@+[+ {+ "test_id": "wip_4000l_vs_600l",+ "description": "C2 battle report 2734693171371185",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 4000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 600+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 281.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T00:52:23.000Z",+ "randomseed": 1790383944,+ "attacker": 3958,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171371185",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T00-52-51.172Z-d1b17d0c-2e97-4d39-a00e-ee5a3285d69f.json",+ "winner": "attacker",+ "attacker": {+ "troops": 4000,+ "survivors": 3958,+ "losses": 0,+ "injured": 15,+ "lightly_injured": 27,+ "kills": 210+ },+ "defender": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 15+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 4000,+ "survivors": 3958,+ "losses": 0,+ "injured": 15,+ "lightly_injured": 27,+ "kills": 210+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 15+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_renee_skill_isolation/gwen_only_before_s2.json===================================================================--- testcases/emulator_verified/gwen_renee_skill_isolation/gwen_only_before_s2.json prev run+++ testcases/emulator_verified/gwen_renee_skill_isolation/gwen_only_before_s2.json this run@@ -0,0 +1,134 @@+[+ {+ "test_id": "gwen_only_before_s2",+ "description": "C2 battle report 2734693171349388",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 4000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 40+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T12:26:23.000Z",+ "randomseed": 1790339184,+ "attacker": 3994,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171349388",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T12-26-48.113Z-12b1a0b3-64b6-44a6-9d04-f7da316031f1.json",+ "winner": "attacker",+ "attacker": {+ "troops": 4000,+ "survivors": 3994,+ "losses": 0,+ "injured": 3,+ "lightly_injured": 3,+ "kills": 14+ },+ "defender": {+ "troops": 40,+ "survivors": 0,+ "losses": 0,+ "injured": 14,+ "lightly_injured": 26,+ "kills": 3+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 4000,+ "survivors": 3994,+ "losses": 0,+ "injured": 3,+ "lightly_injured": 3,+ "kills": 14+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 40,+ "survivors": 0,+ "losses": 0,+ "injured": 14,+ "lightly_injured": 26,+ "kills": 3+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_renee_skill_isolation/gwen_renee_after_s2.json===================================================================--- testcases/emulator_verified/gwen_renee_skill_isolation/gwen_renee_after_s2.json prev run+++ testcases/emulator_verified/gwen_renee_skill_isolation/gwen_renee_after_s2.json this run@@ -0,0 +1,146 @@+[+ {+ "test_id": "gwen_renee_after_s2",+ "description": "C2 battle report 2734693171349608",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 4000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 1450+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T12:32:30.000Z",+ "randomseed": 1790339551,+ "attacker": 3865,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171349608",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T12-32-55.111Z-db52e872-7da9-4bb5-98c9-39935062834b.json",+ "winner": "attacker",+ "attacker": {+ "troops": 4000,+ "survivors": 3865,+ "losses": 0,+ "injured": 48,+ "lightly_injured": 87,+ "kills": 508+ },+ "defender": {+ "troops": 1450,+ "survivors": 0,+ "losses": 0,+ "injured": 508,+ "lightly_injured": 942,+ "kills": 48+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 4000,+ "survivors": 3865,+ "losses": 0,+ "injured": 48,+ "lightly_injured": 87,+ "kills": 508+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 1450,+ "survivors": 0,+ "losses": 0,+ "injured": 508,+ "lightly_injured": 942,+ "kills": 48+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 1,+ "displayed_kills": 8+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 3,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_renee_skill_isolation/gwen_renee_before_s2.json===================================================================--- testcases/emulator_verified/gwen_renee_skill_isolation/gwen_renee_before_s2.json prev run+++ testcases/emulator_verified/gwen_renee_skill_isolation/gwen_renee_before_s2.json this run@@ -0,0 +1,146 @@+[+ {+ "test_id": "gwen_renee_before_s2",+ "description": "C2 battle report 2734693171349444",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 4000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 800+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T12:28:46.000Z",+ "randomseed": 1790339327,+ "attacker": 3940,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171349444",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T12-29-11.127Z-19e7a713-0475-4f28-bfcf-4afa86e2c3ae.json",+ "winner": "attacker",+ "attacker": {+ "troops": 4000,+ "survivors": 3940,+ "losses": 0,+ "injured": 21,+ "lightly_injured": 39,+ "kills": 280+ },+ "defender": {+ "troops": 800,+ "survivors": 0,+ "losses": 0,+ "injured": 280,+ "lightly_injured": 520,+ "kills": 21+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 4000,+ "survivors": 3940,+ "losses": 0,+ "injured": 21,+ "lightly_injured": 39,+ "kills": 280+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 800,+ "survivors": 0,+ "losses": 0,+ "injured": 280,+ "lightly_injured": 520,+ "kills": 21+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_renee_skill_isolation/gwen_renee_first_s2.json===================================================================--- testcases/emulator_verified/gwen_renee_skill_isolation/gwen_renee_first_s2.json prev run+++ testcases/emulator_verified/gwen_renee_skill_isolation/gwen_renee_first_s2.json this run@@ -0,0 +1,146 @@+[+ {+ "test_id": "gwen_renee_first_s2",+ "description": "C2 battle report 2734693171349554",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 4000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 1325+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T12:31:15.000Z",+ "randomseed": 1790339476,+ "attacker": 3883,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171349554",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T12-31-40.130Z-51202676-d0fa-47f5-bc5b-503fd496112a.json",+ "winner": "attacker",+ "attacker": {+ "troops": 4000,+ "survivors": 3883,+ "losses": 0,+ "injured": 41,+ "lightly_injured": 76,+ "kills": 464+ },+ "defender": {+ "troops": 1325,+ "survivors": 0,+ "losses": 0,+ "injured": 464,+ "lightly_injured": 861,+ "kills": 41+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 4000,+ "survivors": 3883,+ "losses": 0,+ "injured": 41,+ "lightly_injured": 76,+ "kills": 464+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 1325,+ "survivors": 0,+ "losses": 0,+ "injured": 464,+ "lightly_injured": 861,+ "kills": 41+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 1,+ "displayed_kills": 8+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 3,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_renee_skill_isolation/gwen_renee_mixed_after_s2.json===================================================================--- testcases/emulator_verified/gwen_renee_skill_isolation/gwen_renee_mixed_after_s2.json prev run+++ testcases/emulator_verified/gwen_renee_skill_isolation/gwen_renee_mixed_after_s2.json this run@@ -0,0 +1,155 @@+[+ {+ "test_id": "gwen_renee_mixed_after_s2",+ "description": "C2 battle report 2734693171349658",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 4000,+ "marksman_t6": 1200+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 2400+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T12:33:44.000Z",+ "randomseed": 1790339625,+ "attacker": 4978,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171349658",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T12-34-09.139Z-823db098-b05e-49e7-af2a-c5a4f03ef326.json",+ "winner": "attacker",+ "attacker": {+ "troops": 5200,+ "survivors": 4978,+ "losses": 0,+ "injured": 78,+ "lightly_injured": 144,+ "kills": 840+ },+ "defender": {+ "troops": 2400,+ "survivors": 0,+ "losses": 0,+ "injured": 840,+ "lightly_injured": 1560,+ "kills": 78+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 4000,+ "survivors": 3778,+ "losses": 0,+ "injured": 78,+ "lightly_injured": 144,+ "kills": 622+ },+ "marksman_t6": {+ "troops": 1200,+ "survivors": 1200,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 218+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 2400,+ "survivors": 0,+ "losses": 0,+ "injured": 840,+ "lightly_injured": 1560,+ "kills": 78+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 2,+ "displayed_kills": 16+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 3,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_renee_skill_isolation/gwen_renee_mixed_before_s2.json===================================================================--- testcases/emulator_verified/gwen_renee_skill_isolation/gwen_renee_mixed_before_s2.json prev run+++ testcases/emulator_verified/gwen_renee_skill_isolation/gwen_renee_mixed_before_s2.json this run@@ -0,0 +1,155 @@+[+ {+ "test_id": "gwen_renee_mixed_before_s2",+ "description": "C2 battle report 2734693171349532",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 4000,+ "marksman_t6": 1200+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 1200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T12:29:59.000Z",+ "randomseed": 1790339400,+ "attacker": 5113,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171349532",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T12-30-24.115Z-f7e369e2-74c5-4600-88a6-d3eee1e67f5d.json",+ "winner": "attacker",+ "attacker": {+ "troops": 5200,+ "survivors": 5113,+ "losses": 0,+ "injured": 31,+ "lightly_injured": 56,+ "kills": 420+ },+ "defender": {+ "troops": 1200,+ "survivors": 0,+ "losses": 0,+ "injured": 420,+ "lightly_injured": 780,+ "kills": 31+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 4000,+ "survivors": 3913,+ "losses": 0,+ "injured": 31,+ "lightly_injured": 56,+ "kills": 328+ },+ "marksman_t6": {+ "troops": 1200,+ "survivors": 1200,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 92+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 1200,+ "survivors": 0,+ "losses": 0,+ "injured": 420,+ "lightly_injured": 780,+ "kills": 31+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_renee_skill_isolation/renee_only_short.json===================================================================--- testcases/emulator_verified/gwen_renee_skill_isolation/renee_only_short.json prev run+++ testcases/emulator_verified/gwen_renee_skill_isolation/renee_only_short.json this run@@ -0,0 +1,135 @@+[+ {+ "test_id": "renee_only_short",+ "description": "C2 battle report 2734693171349427",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 4000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 800+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T12:27:34.000Z",+ "randomseed": 1790339255,+ "attacker": 3940,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171349427",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T12-27-59.114Z-8b56b7fd-a65b-4e20-8561-3adaf9057432.json",+ "winner": "attacker",+ "attacker": {+ "troops": 4000,+ "survivors": 3940,+ "losses": 0,+ "injured": 21,+ "lightly_injured": 39,+ "kills": 280+ },+ "defender": {+ "troops": 800,+ "survivors": 0,+ "losses": 0,+ "injured": 280,+ "lightly_injured": 520,+ "kills": 21+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 4000,+ "survivors": 3940,+ "losses": 0,+ "injured": 21,+ "lightly_injured": 39,+ "kills": 280+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 800,+ "survivors": 0,+ "losses": 0,+ "injured": 280,+ "lightly_injured": 520,+ "kills": 21+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_renee_wall_20260926/renee_500l_vs_gatot_300i.json===================================================================--- testcases/emulator_verified/gwen_renee_wall_20260926/renee_500l_vs_gatot_300i.json prev run+++ testcases/emulator_verified/gwen_renee_wall_20260926/renee_500l_vs_gatot_300i.json this run@@ -0,0 +1,149 @@+[+ {+ "test_id": "renee_500l_vs_gatot_300i",+ "description": "C2 battle report 2734693171382525",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 500+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t9": 300+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T07:19:19.000Z",+ "randomseed": 1790407160,+ "attacker": 0,+ "defender": 229,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171382525",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T07-19-36.111Z-b0079f80-ea2a-4d05-a677-657dffdf50e6.json",+ "winner": "defender",+ "attacker": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 25+ },+ "defender": {+ "troops": 300,+ "survivors": 229,+ "losses": 0,+ "injured": 25,+ "lightly_injured": 46,+ "kills": 175+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 25+ }+ },+ "defender": {+ "infantry_t9": {+ "troops": 300,+ "survivors": 229,+ "losses": 0,+ "injured": 25,+ "lightly_injured": 46,+ "kills": 175+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 49,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Gatot": {+ "King's Bestowal": {+ "triggered": 98,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/gwen_renee_wall_20260926/renee_gwen_500l_vs_gatot_300i.json===================================================================--- testcases/emulator_verified/gwen_renee_wall_20260926/renee_gwen_500l_vs_gatot_300i.json prev run+++ testcases/emulator_verified/gwen_renee_wall_20260926/renee_gwen_500l_vs_gatot_300i.json this run@@ -0,0 +1,165 @@+[+ {+ "test_id": "renee_gwen_500l_vs_gatot_300i",+ "description": "C2 battle report 2734693171382576",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 500+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 434.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t9": 300+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T07:21:54.000Z",+ "randomseed": 1790407315,+ "attacker": 0,+ "defender": 215,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171382576",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T07-22-11.111Z-0a1cc51e-2f29-4036-8fb6-dfb231bc018d.json",+ "winner": "defender",+ "attacker": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 30+ },+ "defender": {+ "troops": 300,+ "survivors": 215,+ "losses": 0,+ "injured": 30,+ "lightly_injured": 55,+ "kills": 175+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 30+ }+ },+ "defender": {+ "infantry_t9": {+ "troops": 300,+ "survivors": 215,+ "losses": 0,+ "injured": 30,+ "lightly_injured": 55,+ "kills": 175+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 16,+ "displayed_kills": null+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 50,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Gatot": {+ "King's Bestowal": {+ "triggered": 100,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/model_checks_20260929/c10_gwen_300l_vs_31000t9l.json===================================================================--- testcases/emulator_verified/model_checks_20260929/c10_gwen_300l_vs_31000t9l.json prev run+++ testcases/emulator_verified/model_checks_20260929/c10_gwen_300l_vs_31000t9l.json this run@@ -0,0 +1,146 @@+[+ {+ "test_id": "c10_gwen_300l_vs_31000t9l",+ "description": "C2 battle report 2734693171529366",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 31000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T13:18:38.000Z",+ "randomseed": 1790687919,+ "attacker": 0,+ "defender": 30981,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171529366",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T13-18-48.158Z-59acb471-6ae9-46a5-9e85-b7c06f5106e9.json",+ "winner": "defender",+ "attacker": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 7+ },+ "defender": {+ "troops": 31000,+ "survivors": 30981,+ "losses": 0,+ "injured": 7,+ "lightly_injured": 12,+ "kills": 105+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 7+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 31000,+ "survivors": 30981,+ "losses": 0,+ "injured": 7,+ "lightly_injured": 12,+ "kills": 105+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": null,+ "displayed_kills": null+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/model_checks_20260929/c11a_bradley_norah_1500l_vs_2000l_3000m.json===================================================================--- testcases/emulator_verified/model_checks_20260929/c11a_bradley_norah_1500l_vs_2000l_3000m.json prev run+++ testcases/emulator_verified/model_checks_20260929/c11a_bradley_norah_1500l_vs_2000l_3000m.json this run@@ -0,0 +1,160 @@+[+ {+ "test_id": "c11a_bradley_norah_1500l_vs_2000l_3000m",+ "description": "C2 battle report 2734693171530112",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Norah": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Bradley": {+ "skill_1": 5,+ "skill_2": 4,+ "skill_3": 3,+ "skill_4": 1+ }+ },+ "troops": {+ "lancer_t6": 1500+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 458.79,+ "defense": 453.04,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 739.42,+ "defense": 735.42,+ "lethality": 375.19,+ "health": 331.96+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 2000,+ "marksman_t6": 3000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T13:47:06.000Z",+ "randomseed": 1790689627,+ "attacker": 0,+ "defender": 1410,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171530112",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T13-47-22.150Z-6fd15df0-004f-4d85-ba66-56c665819418.json",+ "winner": "defender",+ "attacker": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 1257+ },+ "defender": {+ "troops": 5000,+ "survivors": 1410,+ "losses": 0,+ "injured": 1257,+ "lightly_injured": 2333,+ "kills": 525+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 1257+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 2000,+ "survivors": 0,+ "losses": 0,+ "injured": 700,+ "lightly_injured": 1300,+ "kills": 86+ },+ "marksman_t6": {+ "troops": 3000,+ "survivors": 1410,+ "losses": 0,+ "injured": 557,+ "lightly_injured": 1033,+ "kills": 439+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Norah": {+ "Sneak Strike": {+ "triggered": 3,+ "displayed_kills": 52+ },+ "Momentum": {+ "triggered": 6,+ "displayed_kills": null+ }+ },+ "Bradley": {+ "Tactical Assistance": {+ "triggered": 8,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/model_checks_20260929/c11b_bradley_norah_1500l_vs_2000l_3000m.json===================================================================--- testcases/emulator_verified/model_checks_20260929/c11b_bradley_norah_1500l_vs_2000l_3000m.json prev run+++ testcases/emulator_verified/model_checks_20260929/c11b_bradley_norah_1500l_vs_2000l_3000m.json this run@@ -0,0 +1,160 @@+[+ {+ "test_id": "c11b_bradley_norah_1500l_vs_2000l_3000m",+ "description": "C2 battle report 2734693171530118",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Norah": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Bradley": {+ "skill_1": 5,+ "skill_2": 4,+ "skill_3": 3,+ "skill_4": 1+ }+ },+ "troops": {+ "lancer_t6": 1500+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 458.79,+ "defense": 453.04,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 739.42,+ "defense": 735.42,+ "lethality": 375.19,+ "health": 331.96+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 2000,+ "marksman_t6": 3000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T13:47:52.000Z",+ "randomseed": 1790689673,+ "attacker": 0,+ "defender": 140,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171530118",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T13-48-08.136Z-e845c869-615d-478f-b026-1abc0175931e.json",+ "winner": "defender",+ "attacker": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 1701+ },+ "defender": {+ "troops": 5000,+ "survivors": 140,+ "losses": 0,+ "injured": 1701,+ "lightly_injured": 3159,+ "kills": 525+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 1701+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 2000,+ "survivors": 0,+ "losses": 0,+ "injured": 700,+ "lightly_injured": 1300,+ "kills": 77+ },+ "marksman_t6": {+ "troops": 3000,+ "survivors": 140,+ "losses": 0,+ "injured": 1001,+ "lightly_injured": 1859,+ "kills": 448+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Norah": {+ "Sneak Strike": {+ "triggered": 9,+ "displayed_kills": 238+ },+ "Momentum": {+ "triggered": 8,+ "displayed_kills": null+ }+ },+ "Bradley": {+ "Tactical Assistance": {+ "triggered": 11,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/model_checks_20260929/c1a_bradley_norah_1500l_vs_2000i_3000m.json===================================================================--- testcases/emulator_verified/model_checks_20260929/c1a_bradley_norah_1500l_vs_2000i_3000m.json prev run+++ testcases/emulator_verified/model_checks_20260929/c1a_bradley_norah_1500l_vs_2000i_3000m.json this run@@ -0,0 +1,160 @@+[+ {+ "test_id": "c1a_bradley_norah_1500l_vs_2000i_3000m",+ "description": "C2 battle report 2734693171529313",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Norah": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Bradley": {+ "skill_1": 5,+ "skill_2": 4,+ "skill_3": 3,+ "skill_4": 1+ }+ },+ "troops": {+ "lancer_t6": 1500+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 458.79,+ "defense": 453.04,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 739.42,+ "defense": 735.42,+ "lethality": 375.19,+ "health": 331.96+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 2000,+ "marksman_t6": 3000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T13:14:37.000Z",+ "randomseed": 1790687678,+ "attacker": 0,+ "defender": 3613,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171529313",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T13-14-53.142Z-31d86c8d-9b98-4d1b-9d77-90d2e6cf85b2.json",+ "winner": "defender",+ "attacker": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 486+ },+ "defender": {+ "troops": 5000,+ "survivors": 3613,+ "losses": 0,+ "injured": 486,+ "lightly_injured": 901,+ "kills": 525+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 486+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 2000,+ "survivors": 1004,+ "losses": 0,+ "injured": 349,+ "lightly_injured": 647,+ "kills": 93+ },+ "marksman_t6": {+ "troops": 3000,+ "survivors": 2609,+ "losses": 0,+ "injured": 137,+ "lightly_injured": 254,+ "kills": 432+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Norah": {+ "Sneak Strike": {+ "triggered": 7,+ "displayed_kills": 166+ },+ "Momentum": {+ "triggered": 6,+ "displayed_kills": null+ }+ },+ "Bradley": {+ "Tactical Assistance": {+ "triggered": 7,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/model_checks_20260929/c1b_bradley_norah_1500l_vs_2000i_3000m.json===================================================================--- testcases/emulator_verified/model_checks_20260929/c1b_bradley_norah_1500l_vs_2000i_3000m.json prev run+++ testcases/emulator_verified/model_checks_20260929/c1b_bradley_norah_1500l_vs_2000i_3000m.json this run@@ -0,0 +1,160 @@+[+ {+ "test_id": "c1b_bradley_norah_1500l_vs_2000i_3000m",+ "description": "C2 battle report 2734693171529322",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Norah": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Bradley": {+ "skill_1": 5,+ "skill_2": 4,+ "skill_3": 3,+ "skill_4": 1+ }+ },+ "troops": {+ "lancer_t6": 1500+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 458.79,+ "defense": 453.04,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 739.42,+ "defense": 735.42,+ "lethality": 375.19,+ "health": 331.96+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 2000,+ "marksman_t6": 3000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T13:15:22.000Z",+ "randomseed": 1790687723,+ "attacker": 0,+ "defender": 3641,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171529322",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T13-15-38.124Z-d2b3c33c-8cf7-4134-814b-bb247dee7410.json",+ "winner": "defender",+ "attacker": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 477+ },+ "defender": {+ "troops": 5000,+ "survivors": 3641,+ "losses": 0,+ "injured": 477,+ "lightly_injured": 882,+ "kills": 525+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 477+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 2000,+ "survivors": 1011,+ "losses": 0,+ "injured": 347,+ "lightly_injured": 642,+ "kills": 93+ },+ "marksman_t6": {+ "troops": 3000,+ "survivors": 2630,+ "losses": 0,+ "injured": 130,+ "lightly_injured": 240,+ "kills": 432+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Norah": {+ "Sneak Strike": {+ "triggered": 7,+ "displayed_kills": 157+ },+ "Momentum": {+ "triggered": 6,+ "displayed_kills": null+ }+ },+ "Bradley": {+ "Tactical Assistance": {+ "triggered": 7,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/model_checks_20260929/c2_bradley_800m_vs_1000i_1200m.json===================================================================--- testcases/emulator_verified/model_checks_20260929/c2_bradley_800m_vs_1000i_1200m.json prev run+++ testcases/emulator_verified/model_checks_20260929/c2_bradley_800m_vs_1000i_1200m.json this run@@ -0,0 +1,144 @@+[+ {+ "test_id": "c2_bradley_800m_vs_1000i_1200m",+ "description": "C2 battle report 2734693171529139",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Bradley": {+ "skill_1": 5,+ "skill_2": 4,+ "skill_3": 3,+ "skill_4": 1+ }+ },+ "troops": {+ "marksman_t6": 800+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 739.42,+ "defense": 735.42,+ "lethality": 375.19,+ "health": 331.96+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 1000,+ "marksman_t6": 1200+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T13:08:35.000Z",+ "randomseed": 1790687316,+ "attacker": 507,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171529139",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T13-08-51.144Z-4c98341d-7512-4f4c-8ab1-cc1727c14ea5.json",+ "winner": "attacker",+ "attacker": {+ "troops": 800,+ "survivors": 507,+ "losses": 0,+ "injured": 103,+ "lightly_injured": 190,+ "kills": 770+ },+ "defender": {+ "troops": 2200,+ "survivors": 0,+ "losses": 0,+ "injured": 770,+ "lightly_injured": 1430,+ "kills": 103+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 800,+ "survivors": 507,+ "losses": 0,+ "injured": 103,+ "lightly_injured": 190,+ "kills": 770+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 12+ },+ "marksman_t6": {+ "troops": 1200,+ "survivors": 0,+ "losses": 0,+ "injured": 420,+ "lightly_injured": 780,+ "kills": 91+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Bradley": {+ "Tactical Assistance": {+ "triggered": 5,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/model_checks_20260929/c3_renee_gwen_1000l_vs_8000t9m.json===================================================================--- testcases/emulator_verified/model_checks_20260929/c3_renee_gwen_1000l_vs_8000t9m.json prev run+++ testcases/emulator_verified/model_checks_20260929/c3_renee_gwen_1000l_vs_8000t9m.json this run@@ -0,0 +1,158 @@+[+ {+ "test_id": "c3_renee_gwen_1000l_vs_8000t9m",+ "description": "C2 battle report 2734693171529178",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 607.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "marksman_t9": 8000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T13:09:20.000Z",+ "randomseed": 1790687361,+ "attacker": 0,+ "defender": 6227,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171529178",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T13-09-36.121Z-513dcf5d-014f-4802-970c-1e6138be8711.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 621+ },+ "defender": {+ "troops": 8000,+ "survivors": 6227,+ "losses": 0,+ "injured": 621,+ "lightly_injured": 1152,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 621+ }+ },+ "defender": {+ "marksman_t9": {+ "troops": 8000,+ "survivors": 6227,+ "losses": 0,+ "injured": 621,+ "lightly_injured": 1152,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 2,+ "displayed_kills": 6+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 7,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Volley": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/model_checks_20260929/c4_renee_1000l_vs_8000t9m.json===================================================================--- testcases/emulator_verified/model_checks_20260929/c4_renee_1000l_vs_8000t9m.json prev run+++ testcases/emulator_verified/model_checks_20260929/c4_renee_1000l_vs_8000t9m.json this run@@ -0,0 +1,142 @@+[+ {+ "test_id": "c4_renee_1000l_vs_8000t9m",+ "description": "C2 battle report 2734693171529191",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 607.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "marksman_t9": 8000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T13:10:06.000Z",+ "randomseed": 1790687407,+ "attacker": 0,+ "defender": 6427,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171529191",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T13-10-22.147Z-d8f4dd30-b5e2-4904-a898-82a2465e998d.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 551+ },+ "defender": {+ "troops": 8000,+ "survivors": 6427,+ "losses": 0,+ "injured": 551,+ "lightly_injured": 1022,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 551+ }+ },+ "defender": {+ "marksman_t9": {+ "troops": 8000,+ "survivors": 6427,+ "losses": 0,+ "injured": 551,+ "lightly_injured": 1022,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 7,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Volley": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/model_checks_20260929/c5_gordon_1000l_vs_gatot_3000i.json===================================================================--- testcases/emulator_verified/model_checks_20260929/c5_gordon_1000l_vs_gatot_3000i.json prev run+++ testcases/emulator_verified/model_checks_20260929/c5_gordon_1000l_vs_gatot_3000i.json this run@@ -0,0 +1,157 @@+[+ {+ "test_id": "c5_gordon_1000l_vs_gatot_3000i",+ "description": "C2 battle report 2734693171529201",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 3000+ },+ "stats": {+ "infantry": {+ "attack": 628.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T13:10:51.000Z",+ "randomseed": 1790687452,+ "attacker": 0,+ "defender": 2944,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171529201",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T13-11-07.126Z-178d1f4d-9978-4ab1-9c00-b78bd19c38ea.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 20+ },+ "defender": {+ "troops": 3000,+ "survivors": 2944,+ "losses": 0,+ "injured": 20,+ "lightly_injured": 36,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 20+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 3000,+ "survivors": 2944,+ "losses": 0,+ "injured": 20,+ "lightly_injured": 36,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": 11,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 23,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 15,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Gatot": {+ "King's Bestowal": {+ "triggered": 46,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/model_checks_20260929/c6_gordon_1000l_vs_10000t9m.json===================================================================--- testcases/emulator_verified/model_checks_20260929/c6_gordon_1000l_vs_10000t9m.json prev run+++ testcases/emulator_verified/model_checks_20260929/c6_gordon_1000l_vs_10000t9m.json this run@@ -0,0 +1,150 @@+[+ {+ "test_id": "c6_gordon_1000l_vs_10000t9m",+ "description": "C2 battle report 2734693171529227",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "marksman_t9": 10000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T13:11:36.000Z",+ "randomseed": 1790687497,+ "attacker": 0,+ "defender": 9376,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171529227",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T13-11-52.138Z-0b2481f1-89f2-46b7-aca1-2bebd94b7c45.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 219+ },+ "defender": {+ "troops": 10000,+ "survivors": 9376,+ "losses": 0,+ "injured": 219,+ "lightly_injured": 405,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 219+ }+ },+ "defender": {+ "marksman_t9": {+ "troops": 10000,+ "survivors": 9376,+ "losses": 0,+ "injured": 219,+ "lightly_injured": 405,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": 2,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 5,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 3,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Volley": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/model_checks_20260929/c7_noheroes_1000l_vs_10000t9m.json===================================================================--- testcases/emulator_verified/model_checks_20260929/c7_noheroes_1000l_vs_10000t9m.json prev run+++ testcases/emulator_verified/model_checks_20260929/c7_noheroes_1000l_vs_10000t9m.json this run@@ -0,0 +1,128 @@+[+ {+ "test_id": "c7_noheroes_1000l_vs_10000t9m",+ "description": "C2 battle report 2734693171529242",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "marksman_t9": 10000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T13:12:21.000Z",+ "randomseed": 1790687542,+ "attacker": 0,+ "defender": 9840,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171529242",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T13-12-37.119Z-fad2388e-0d80-4d88-a5da-5ac6ee33c272.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 56+ },+ "defender": {+ "troops": 10000,+ "survivors": 9840,+ "losses": 0,+ "injured": 56,+ "lightly_injured": 104,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 56+ }+ },+ "defender": {+ "marksman_t9": {+ "troops": 10000,+ "survivors": 9840,+ "losses": 0,+ "injured": 56,+ "lightly_injured": 104,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {+ "Troop skills": {+ "Volley": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/model_checks_20260929/c8_gordon_gwen_300l_vs_31000t9l.json===================================================================--- testcases/emulator_verified/model_checks_20260929/c8_gordon_gwen_300l_vs_31000t9l.json prev run+++ testcases/emulator_verified/model_checks_20260929/c8_gordon_gwen_300l_vs_31000t9l.json this run@@ -0,0 +1,166 @@+[+ {+ "test_id": "c8_gordon_gwen_300l_vs_31000t9l",+ "description": "C2 battle report 2734693171529259",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 31000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T13:13:06.000Z",+ "randomseed": 1790687587,+ "attacker": 0,+ "defender": 30939,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171529259",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T13-13-22.148Z-4dd40c8b-9c3d-490b-98c5-7af3eed54aa3.json",+ "winner": "defender",+ "attacker": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 22+ },+ "defender": {+ "troops": 31000,+ "survivors": 30939,+ "losses": 0,+ "injured": 22,+ "lightly_injured": 39,+ "kills": 105+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 22+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 31000,+ "survivors": 30939,+ "losses": 0,+ "injured": 22,+ "lightly_injured": 39,+ "kills": 105+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": null,+ "displayed_kills": null+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Gordon": {+ "Toxic Release": {+ "triggered": 1,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 2,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/model_checks_20260929/c9_gordon_300l_vs_31000t9l.json===================================================================--- testcases/emulator_verified/model_checks_20260929/c9_gordon_300l_vs_31000t9l.json prev run+++ testcases/emulator_verified/model_checks_20260929/c9_gordon_300l_vs_31000t9l.json this run@@ -0,0 +1,150 @@+[+ {+ "test_id": "c9_gordon_300l_vs_31000t9l",+ "description": "C2 battle report 2734693171529360",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gordon": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_3": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 493.62,+ "defense": 487.87,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 31000+ },+ "stats": {+ "infantry": {+ "attack": 258.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T13:17:52.000Z",+ "randomseed": 1790687873,+ "attacker": 0,+ "defender": 30946,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171529360",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T13-18-08.153Z-849cc59e-a541-48ac-9bdd-7c0229e92cee.json",+ "winner": "defender",+ "attacker": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 19+ },+ "defender": {+ "troops": 31000,+ "survivors": 30946,+ "losses": 0,+ "injured": 19,+ "lightly_injured": 35,+ "kills": 105+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 19+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 31000,+ "survivors": 30946,+ "losses": 0,+ "injured": 19,+ "lightly_injured": 35,+ "kills": 105+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gordon": {+ "Toxic Release": {+ "triggered": 1,+ "displayed_kills": null+ },+ "Venom Infusion": {+ "triggered": 2,+ "displayed_kills": null+ },+ "Chemical Terror": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/remaining_parity_20260929/natalia_mixed_control.json===================================================================--- testcases/emulator_verified/remaining_parity_20260929/natalia_mixed_control.json prev run+++ testcases/emulator_verified/remaining_parity_20260929/natalia_mixed_control.json this run@@ -0,0 +1,619 @@+[+ {+ "test_id": "natalia_mixed_control",+ "description": "C2 battle report 2734693171534211",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Sergey": {+ "skill_1": 2,+ "skill_2": 2+ },+ "Molly": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_4": 0+ },+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 800,+ "lancer_t6": 250,+ "marksman_t6": 700+ },+ "stats": {+ "infantry": {+ "attack": 347.14,+ "defense": 338.69,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 259.81,+ "defense": 259.11,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Natalia": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 200,+ "lancer_t6": 100,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 346.18,+ "defense": 334.18,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T15:53:51.000Z",+ "randomseed": 1790697232,+ "attacker": 1644,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171534211",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T15-54-16.107Z-1937034a-2806-4a67-9bd8-64ad000f820e.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1750,+ "survivors": 1644,+ "losses": 0,+ "injured": 38,+ "lightly_injured": 68,+ "kills": 140+ },+ "defender": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 38+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 800,+ "survivors": 694,+ "losses": 0,+ "injured": 38,+ "lightly_injured": 68,+ "kills": 28+ },+ "lancer_t6": {+ "troops": 250,+ "survivors": 250,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 35+ },+ "marksman_t6": {+ "troops": 700,+ "survivors": 700,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 77+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 5+ },+ "lancer_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 12+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 21+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Molly": {+ "Ice Dominion": {+ "triggered": 37,+ "displayed_kills": 15+ },+ "Snow's Grace": {+ "triggered": 11,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Natalia": {+ "Feral Protection": {+ "triggered": 8,+ "displayed_kills": null+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-29T15:54:55.000Z",+ "randomseed": 1790697296,+ "attacker": 1639,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171534240",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T15-55-20.110Z-106c1a4d-2e3c-405b-911c-d41b1b9b3300.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1750,+ "survivors": 1639,+ "losses": 0,+ "injured": 39,+ "lightly_injured": 72,+ "kills": 140+ },+ "defender": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 39+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 800,+ "survivors": 689,+ "losses": 0,+ "injured": 39,+ "lightly_injured": 72,+ "kills": 25+ },+ "lancer_t6": {+ "troops": 250,+ "survivors": 250,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 35+ },+ "marksman_t6": {+ "troops": 700,+ "survivors": 700,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 80+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 5+ },+ "lancer_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 12+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 22+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Molly": {+ "Ice Dominion": {+ "triggered": 36,+ "displayed_kills": 14+ },+ "Snow's Grace": {+ "triggered": 11,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Natalia": {+ "Feral Protection": {+ "triggered": 10,+ "displayed_kills": null+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-29T15:55:59.000Z",+ "randomseed": 1790697360,+ "attacker": 1640,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171534267",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T15-56-24.102Z-abcb3f3e-98b7-4cb3-b250-b01d8de3ad40.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1750,+ "survivors": 1640,+ "losses": 0,+ "injured": 39,+ "lightly_injured": 71,+ "kills": 140+ },+ "defender": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 39+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 800,+ "survivors": 690,+ "losses": 0,+ "injured": 39,+ "lightly_injured": 71,+ "kills": 26+ },+ "lancer_t6": {+ "troops": 250,+ "survivors": 250,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 36+ },+ "marksman_t6": {+ "troops": 700,+ "survivors": 700,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 78+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 5+ },+ "lancer_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 12+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 22+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Molly": {+ "Ice Dominion": {+ "triggered": 37,+ "displayed_kills": 12+ },+ "Snow's Grace": {+ "triggered": 12,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Natalia": {+ "Feral Protection": {+ "triggered": 10,+ "displayed_kills": null+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-29T15:57:03.000Z",+ "randomseed": 1790697424,+ "attacker": 1637,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171534275",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T15-57-28.100Z-9a9a157d-357b-4ff6-a397-a9115011cd67.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1750,+ "survivors": 1637,+ "losses": 0,+ "injured": 40,+ "lightly_injured": 73,+ "kills": 140+ },+ "defender": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 40+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 800,+ "survivors": 687,+ "losses": 0,+ "injured": 40,+ "lightly_injured": 73,+ "kills": 23+ },+ "lancer_t6": {+ "troops": 250,+ "survivors": 250,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 35+ },+ "marksman_t6": {+ "troops": 700,+ "survivors": 700,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 82+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 6+ },+ "lancer_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 13+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 21+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Molly": {+ "Ice Dominion": {+ "triggered": 30,+ "displayed_kills": 9+ },+ "Snow's Grace": {+ "triggered": 9,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Natalia": {+ "Feral Protection": {+ "triggered": 9,+ "displayed_kills": null+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-29T15:58:07.000Z",+ "randomseed": 1790697488,+ "attacker": 1646,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171534283",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T15-58-32.102Z-40aa4d17-bf4a-471e-b74f-d537b68e9138.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1750,+ "survivors": 1646,+ "losses": 0,+ "injured": 37,+ "lightly_injured": 67,+ "kills": 140+ },+ "defender": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 37+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 800,+ "survivors": 696,+ "losses": 0,+ "injured": 37,+ "lightly_injured": 67,+ "kills": 26+ },+ "lancer_t6": {+ "troops": 250,+ "survivors": 250,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 35+ },+ "marksman_t6": {+ "troops": 700,+ "survivors": 700,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 79+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 5+ },+ "lancer_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 11+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 21+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Molly": {+ "Ice Dominion": {+ "triggered": 34,+ "displayed_kills": 10+ },+ "Snow's Grace": {+ "triggered": 14,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Natalia": {+ "Feral Protection": {+ "triggered": 9,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/remaining_parity_20260929/six_hero_mixed_control.json===================================================================--- testcases/emulator_verified/remaining_parity_20260929/six_hero_mixed_control.json prev run+++ testcases/emulator_verified/remaining_parity_20260929/six_hero_mixed_control.json this run@@ -0,0 +1,699 @@+[+ {+ "test_id": "six_hero_mixed_control",+ "description": "C2 battle report 2734693171534393",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Sergey": {+ "skill_1": 2,+ "skill_2": 2+ },+ "Molly": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_4": 0+ },+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 800,+ "lancer_t6": 250,+ "marksman_t6": 700+ },+ "stats": {+ "infantry": {+ "attack": 347.14,+ "defense": 338.69,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 259.81,+ "defense": 259.11,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Natalia": {+ "skill_1": 2,+ "skill_2": 2,+ "skill_4": 0+ },+ "Patrick": {+ "skill_1": 3,+ "skill_2": 2+ },+ "Alonso": {+ "skill_1": 3,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 200,+ "lancer_t6": 100,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 346.18,+ "defense": 334.18,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 396.69,+ "defense": 395.94,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 410.06,+ "defense": 411.06,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T16:02:59.000Z",+ "randomseed": 1790697780,+ "attacker": 1494,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171534393",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T16-03-24.105Z-ddf53900-7b4d-484a-bb12-aa89c5294599.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1750,+ "survivors": 1494,+ "losses": 0,+ "injured": 90,+ "lightly_injured": 166,+ "kills": 140+ },+ "defender": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 90+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 800,+ "survivors": 544,+ "losses": 0,+ "injured": 90,+ "lightly_injured": 166,+ "kills": 18+ },+ "lancer_t6": {+ "troops": 250,+ "survivors": 250,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 36+ },+ "marksman_t6": {+ "troops": 700,+ "survivors": 700,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 86+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 9+ },+ "lancer_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 28+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 53+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Molly": {+ "Ice Dominion": {+ "triggered": 51,+ "displayed_kills": 14+ },+ "Snow's Grace": {+ "triggered": 9,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Alonso": {+ "Poison Harpoon": {+ "triggered": 40,+ "displayed_kills": 14+ },+ "Iron Strength": {+ "triggered": 22,+ "displayed_kills": null+ },+ "Onslaught": {+ "triggered": 12,+ "displayed_kills": null+ }+ },+ "Natalia": {+ "Feral Protection": {+ "triggered": 13,+ "displayed_kills": null+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-29T16:04:03.000Z",+ "randomseed": 1790697844,+ "attacker": 1501,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171534417",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T16-04-28.098Z-4aaf9dd2-899b-4127-9132-c4a30171c39c.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1750,+ "survivors": 1501,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 161,+ "kills": 140+ },+ "defender": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 88+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 800,+ "survivors": 551,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 161,+ "kills": 20+ },+ "lancer_t6": {+ "troops": 250,+ "survivors": 250,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 38+ },+ "marksman_t6": {+ "troops": 700,+ "survivors": 700,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 82+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 9+ },+ "lancer_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 28+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 51+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Molly": {+ "Ice Dominion": {+ "triggered": 49,+ "displayed_kills": 11+ },+ "Snow's Grace": {+ "triggered": 10,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Alonso": {+ "Poison Harpoon": {+ "triggered": 48,+ "displayed_kills": 17+ },+ "Iron Strength": {+ "triggered": 17,+ "displayed_kills": null+ },+ "Onslaught": {+ "triggered": 9,+ "displayed_kills": null+ }+ },+ "Natalia": {+ "Feral Protection": {+ "triggered": 8,+ "displayed_kills": null+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-29T16:05:07.000Z",+ "randomseed": 1790697908,+ "attacker": 1494,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171534441",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T16-05-32.103Z-94f7eb15-c2d4-4e42-a97a-c18ee930aac2.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1750,+ "survivors": 1494,+ "losses": 0,+ "injured": 90,+ "lightly_injured": 166,+ "kills": 140+ },+ "defender": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 90+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 800,+ "survivors": 544,+ "losses": 0,+ "injured": 90,+ "lightly_injured": 166,+ "kills": 20+ },+ "lancer_t6": {+ "troops": 250,+ "survivors": 250,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 36+ },+ "marksman_t6": {+ "troops": 700,+ "survivors": 700,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 84+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 9+ },+ "lancer_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 31+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 50+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Molly": {+ "Ice Dominion": {+ "triggered": 39,+ "displayed_kills": 9+ },+ "Snow's Grace": {+ "triggered": 10,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Alonso": {+ "Poison Harpoon": {+ "triggered": 33,+ "displayed_kills": 13+ },+ "Iron Strength": {+ "triggered": 20,+ "displayed_kills": null+ },+ "Onslaught": {+ "triggered": 12,+ "displayed_kills": null+ }+ },+ "Natalia": {+ "Feral Protection": {+ "triggered": 14,+ "displayed_kills": null+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-29T16:06:11.000Z",+ "randomseed": 1790697972,+ "attacker": 1477,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171534596",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T16-06-36.132Z-5c0c2252-b430-4009-9eda-82a55330fbdf.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1750,+ "survivors": 1477,+ "losses": 0,+ "injured": 96,+ "lightly_injured": 177,+ "kills": 140+ },+ "defender": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 96+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 800,+ "survivors": 527,+ "losses": 0,+ "injured": 96,+ "lightly_injured": 177,+ "kills": 20+ },+ "lancer_t6": {+ "troops": 250,+ "survivors": 250,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 36+ },+ "marksman_t6": {+ "troops": 700,+ "survivors": 700,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 84+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 9+ },+ "lancer_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 30+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 57+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Molly": {+ "Ice Dominion": {+ "triggered": 36,+ "displayed_kills": 8+ },+ "Snow's Grace": {+ "triggered": 8,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Alonso": {+ "Poison Harpoon": {+ "triggered": 42,+ "displayed_kills": 17+ },+ "Iron Strength": {+ "triggered": 14,+ "displayed_kills": null+ },+ "Onslaught": {+ "triggered": 12,+ "displayed_kills": null+ }+ },+ "Natalia": {+ "Feral Protection": {+ "triggered": 18,+ "displayed_kills": null+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-29T16:07:15.000Z",+ "randomseed": 1790698036,+ "attacker": 1509,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171534697",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T16-07-40.111Z-89121569-7701-4ccb-a754-d9d92b5801ed.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1750,+ "survivors": 1509,+ "losses": 0,+ "injured": 85,+ "lightly_injured": 156,+ "kills": 140+ },+ "defender": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 85+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 800,+ "survivors": 559,+ "losses": 0,+ "injured": 85,+ "lightly_injured": 156,+ "kills": 22+ },+ "lancer_t6": {+ "troops": 250,+ "survivors": 250,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 37+ },+ "marksman_t6": {+ "troops": 700,+ "survivors": 700,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 81+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 9+ },+ "lancer_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 27+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 49+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Molly": {+ "Ice Dominion": {+ "triggered": 47,+ "displayed_kills": 14+ },+ "Snow's Grace": {+ "triggered": 13,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Alonso": {+ "Poison Harpoon": {+ "triggered": 38,+ "displayed_kills": 12+ },+ "Iron Strength": {+ "triggered": 11,+ "displayed_kills": null+ },+ "Onslaught": {+ "triggered": 9,+ "displayed_kills": null+ }+ },+ "Natalia": {+ "Feral Protection": {+ "triggered": 14,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_benign_controls_20260929/renee_jasser_mixed.json===================================================================--- testcases/emulator_verified/renee_benign_controls_20260929/renee_jasser_mixed.json prev run+++ testcases/emulator_verified/renee_benign_controls_20260929/renee_jasser_mixed.json this run@@ -0,0 +1,157 @@+[+ {+ "test_id": "renee_jasser_mixed",+ "description": "C2 battle report 2734693171519542",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 100,+ "lancer_t6": 300,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 250+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T04:21:07.000Z",+ "randomseed": 1790655668,+ "attacker": 485,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171519542",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T04-21-32.177Z-9fdf000c-3acd-496a-b7f4-1c2567c31d12.json",+ "winner": "attacker",+ "attacker": {+ "troops": 500,+ "survivors": 485,+ "losses": 0,+ "injured": 6,+ "lightly_injured": 9,+ "kills": 88+ },+ "defender": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 6+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 100,+ "survivors": 85,+ "losses": 0,+ "injured": 6,+ "lightly_injured": 9,+ "kills": 5+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 300,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 66+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 100,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 17+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 6+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 3,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_benign_controls_20260929/renee_jasser_pure.json===================================================================--- testcases/emulator_verified/renee_benign_controls_20260929/renee_jasser_pure.json prev run+++ testcases/emulator_verified/renee_benign_controls_20260929/renee_jasser_pure.json this run@@ -0,0 +1,139 @@+[+ {+ "test_id": "renee_jasser_pure",+ "description": "C2 battle report 2734693171519423",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "lancer_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T04:17:55.000Z",+ "randomseed": 1790655476,+ "attacker": 285,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171519423",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T04-18-20.145Z-5fa2ee37-9f16-435a-bad0-cb0a6df74622.json",+ "winner": "attacker",+ "attacker": {+ "troops": 300,+ "survivors": 285,+ "losses": 0,+ "injured": 6,+ "lightly_injured": 9,+ "kills": 53+ },+ "defender": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 6+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 300,+ "survivors": 285,+ "losses": 0,+ "injured": 6,+ "lightly_injured": 9,+ "kills": 53+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 6+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 3,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_benign_controls_20260929/renee_sergey_mixed.json===================================================================--- testcases/emulator_verified/renee_benign_controls_20260929/renee_sergey_mixed.json prev run+++ testcases/emulator_verified/renee_benign_controls_20260929/renee_sergey_mixed.json this run@@ -0,0 +1,157 @@+[+ {+ "test_id": "renee_sergey_mixed",+ "description": "C2 battle report 2734693171519591",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Sergey": {+ "skill_1": 2,+ "skill_2": 2+ }+ },+ "troops": {+ "infantry_t6": 100,+ "lancer_t6": 300,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 346.14,+ "defense": 338.69,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 250+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T04:22:11.000Z",+ "randomseed": 1790655732,+ "attacker": 489,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171519591",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T04-22-36.187Z-4c2d0893-258b-4984-a1b1-0bf9ee2ebc6c.json",+ "winner": "attacker",+ "attacker": {+ "troops": 500,+ "survivors": 489,+ "losses": 0,+ "injured": 4,+ "lightly_injured": 7,+ "kills": 88+ },+ "defender": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 4+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 100,+ "survivors": 89,+ "losses": 0,+ "injured": 4,+ "lightly_injured": 7,+ "kills": 6+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 300,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 66+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 100,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 16+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 4+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 3,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_benign_controls_20260929/renee_sergey_pure.json===================================================================--- testcases/emulator_verified/renee_benign_controls_20260929/renee_sergey_pure.json prev run+++ testcases/emulator_verified/renee_benign_controls_20260929/renee_sergey_pure.json this run@@ -0,0 +1,139 @@+[+ {+ "test_id": "renee_sergey_pure",+ "description": "C2 battle report 2734693171519474",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Sergey": {+ "skill_1": 2,+ "skill_2": 2+ }+ },+ "troops": {+ "lancer_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 346.14,+ "defense": 338.69,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T04:18:59.000Z",+ "randomseed": 1790655540,+ "attacker": 287,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171519474",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T04-19-24.149Z-ea29432b-6a52-4924-ac50-e06e631ce7d7.json",+ "winner": "attacker",+ "attacker": {+ "troops": 300,+ "survivors": 287,+ "losses": 0,+ "injured": 5,+ "lightly_injured": 8,+ "kills": 53+ },+ "defender": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 5+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 300,+ "survivors": 287,+ "losses": 0,+ "injured": 5,+ "lightly_injured": 8,+ "kills": 53+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 5+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 3,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_benign_controls_20260929/renee_solo_mixed.json===================================================================--- testcases/emulator_verified/renee_benign_controls_20260929/renee_solo_mixed.json prev run+++ testcases/emulator_verified/renee_benign_controls_20260929/renee_solo_mixed.json this run@@ -0,0 +1,153 @@+[+ {+ "test_id": "renee_solo_mixed",+ "description": "C2 battle report 2734693171519498",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 100,+ "lancer_t6": 300,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 250+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T04:20:03.000Z",+ "randomseed": 1790655604,+ "attacker": 484,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171519498",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T04-20-28.161Z-ba28cbf5-5cfb-4f25-a9f8-7c2782050b65.json",+ "winner": "attacker",+ "attacker": {+ "troops": 500,+ "survivors": 484,+ "losses": 0,+ "injured": 6,+ "lightly_injured": 10,+ "kills": 88+ },+ "defender": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 6+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 100,+ "survivors": 84,+ "losses": 0,+ "injured": 6,+ "lightly_injured": 10,+ "kills": 4+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 300,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 67+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 100,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 17+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 6+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 4,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_benign_controls_20260929/renee_solo_pure.json===================================================================--- testcases/emulator_verified/renee_benign_controls_20260929/renee_solo_pure.json prev run+++ testcases/emulator_verified/renee_benign_controls_20260929/renee_solo_pure.json this run@@ -0,0 +1,135 @@+[+ {+ "test_id": "renee_solo_pure",+ "description": "C2 battle report 2734693171519405",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T04:16:42.000Z",+ "randomseed": 1790655403,+ "attacker": 285,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171519405",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T04-17-07.191Z-9138f3a3-7630-449d-a9dd-e1c2a7a91ab7.json",+ "winner": "attacker",+ "attacker": {+ "troops": 300,+ "survivors": 285,+ "losses": 0,+ "injured": 6,+ "lightly_injured": 9,+ "kills": 53+ },+ "defender": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 6+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 300,+ "survivors": 285,+ "losses": 0,+ "injured": 6,+ "lightly_injured": 9,+ "kills": 53+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 6+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 3,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/no_infantry_vs_infantry.json===================================================================--- testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/no_infantry_vs_infantry.json prev run+++ testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/no_infantry_vs_infantry.json this run@@ -0,0 +1,160 @@+[+ {+ "test_id": "no_infantry_vs_infantry",+ "description": "C2 battle report 2734693171422654",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 50,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 1446+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-27T02:12:14.000Z",+ "randomseed": 1790475135,+ "attacker": 0,+ "defender": 966,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171422654",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-27T02-12-29.673Z-312f5bf4-5b0a-48d1-b81b-760c51e3f572.json",+ "winner": "defender",+ "attacker": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 168+ },+ "defender": {+ "troops": 1446,+ "survivors": 966,+ "losses": 0,+ "injured": 168,+ "lightly_injured": 312,+ "kills": 88+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 21+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 147+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1446,+ "survivors": 966,+ "losses": 0,+ "injured": 168,+ "lightly_injured": 312,+ "kills": 88+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 14,+ "displayed_kills": 3+ },+ "Blastmaster": {+ "triggered": 14,+ "displayed_kills": 2+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 35,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/no_infantry_vs_lancer.json===================================================================--- testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/no_infantry_vs_lancer.json prev run+++ testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/no_infantry_vs_lancer.json this run@@ -0,0 +1,160 @@+[+ {+ "test_id": "no_infantry_vs_lancer",+ "description": "C2 battle report 2734693171422818",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 200,+ "marksman_t6": 50+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 2567+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-27T02:14:30.000Z",+ "randomseed": 1790475271,+ "attacker": 0,+ "defender": 1347,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171422818",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-27T02-14-45.797Z-75a31864-11a5-494d-aeef-9c528b96e6e9.json",+ "winner": "defender",+ "attacker": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 427+ },+ "defender": {+ "troops": 2567,+ "survivors": 1347,+ "losses": 0,+ "injured": 427,+ "lightly_injured": 793,+ "kills": 88+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 251+ },+ "marksman_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 176+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 2567,+ "survivors": 1347,+ "losses": 0,+ "injured": 427,+ "lightly_injured": 793,+ "kills": 88+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 9,+ "displayed_kills": 5+ },+ "Blastmaster": {+ "triggered": 6,+ "displayed_kills": 2+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 15,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/no_marksmen_vs_infantry.json===================================================================--- testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/no_marksmen_vs_infantry.json prev run+++ testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/no_marksmen_vs_infantry.json this run@@ -0,0 +1,160 @@+[+ {+ "test_id": "no_marksmen_vs_infantry",+ "description": "C2 battle report 2734693171422553",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 50,+ "lancer_t6": 50+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 1446+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-27T02:11:29.000Z",+ "randomseed": 1790475090,+ "attacker": 0,+ "defender": 1077,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171422553",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-27T02-11-44.802Z-6355a0d9-4319-40ec-a219-c23e1d98fc62.json",+ "winner": "defender",+ "attacker": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 36,+ "lightly_injured": 64,+ "kills": 130+ },+ "defender": {+ "troops": 1446,+ "survivors": 1077,+ "losses": 0,+ "injured": 130,+ "lightly_injured": 239,+ "kills": 36+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 6+ },+ "lancer_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 124+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1446,+ "survivors": 1077,+ "losses": 0,+ "injured": 130,+ "lightly_injured": 239,+ "kills": 36+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 23,+ "displayed_kills": 1+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 43,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/no_marksmen_vs_lancer.json===================================================================--- testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/no_marksmen_vs_lancer.json prev run+++ testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/no_marksmen_vs_lancer.json this run@@ -0,0 +1,160 @@+[+ {+ "test_id": "no_marksmen_vs_lancer",+ "description": "C2 battle report 2734693171422775",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 50,+ "lancer_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 2567+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-27T02:13:45.000Z",+ "randomseed": 1790475226,+ "attacker": 0,+ "defender": 1065,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171422775",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-27T02-14-00.652Z-428012df-7f15-4bdd-aa28-7a33a7642391.json",+ "winner": "defender",+ "attacker": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 526+ },+ "defender": {+ "troops": 2567,+ "survivors": 1065,+ "losses": 0,+ "injured": 526,+ "lightly_injured": 976,+ "kills": 88+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 9+ },+ "lancer_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 517+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 2567,+ "survivors": 1065,+ "losses": 0,+ "injured": 526,+ "lightly_injured": 976,+ "kills": 88+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 7,+ "displayed_kills": 6+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 20,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/only_lancers_vs_infantry.json===================================================================--- testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/only_lancers_vs_infantry.json prev run+++ testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/only_lancers_vs_infantry.json this run@@ -0,0 +1,151 @@+[+ {+ "test_id": "only_lancers_vs_infantry",+ "description": "C2 battle report 2734693171422497",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 50+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 1446+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-27T02:10:44.000Z",+ "randomseed": 1790475045,+ "attacker": 0,+ "defender": 1360,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171422497",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-27T02-10-59.679Z-9036b338-46ac-4012-80c6-7008b31382d7.json",+ "winner": "defender",+ "attacker": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 31+ },+ "defender": {+ "troops": 1446,+ "survivors": 1360,+ "losses": 0,+ "injured": 31,+ "lightly_injured": 55,+ "kills": 18+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 31+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1446,+ "survivors": 1360,+ "losses": 0,+ "injured": 31,+ "lightly_injured": 55,+ "kills": 18+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 6,+ "displayed_kills": null+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 20,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/only_lancers_vs_lancer.json===================================================================--- testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/only_lancers_vs_lancer.json prev run+++ testcases/emulator_verified/renee_gwen_lancer_isolation_20260927/only_lancers_vs_lancer.json this run@@ -0,0 +1,151 @@+[+ {+ "test_id": "only_lancers_vs_lancer",+ "description": "C2 battle report 2734693171422716",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 2567+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-27T02:13:00.000Z",+ "randomseed": 1790475181,+ "attacker": 0,+ "defender": 1759,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171422716",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-27T02-13-15.818Z-5522d97c-9e3c-412e-b640-317d5dab5998.json",+ "winner": "defender",+ "attacker": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 283+ },+ "defender": {+ "troops": 2567,+ "survivors": 1759,+ "losses": 0,+ "injured": 283,+ "lightly_injured": 525,+ "kills": 70+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 283+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 2567,+ "survivors": 1759,+ "losses": 0,+ "injured": 283,+ "lightly_injured": 525,+ "kills": 70+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 4,+ "displayed_kills": 3+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 14,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_no_lancers_20260927/no_lancers_1.json===================================================================--- testcases/emulator_verified/renee_gwen_no_lancers_20260927/no_lancers_1.json prev run+++ testcases/emulator_verified/renee_gwen_no_lancers_20260927/no_lancers_1.json this run@@ -0,0 +1,154 @@+[+ {+ "test_id": "no_lancers_1",+ "description": "C2 battle report 2734693171421999",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 50,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 1446+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-27T02:03:24.000Z",+ "randomseed": 1790474605,+ "attacker": 0,+ "defender": 968,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171421999",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-27T02-03-39.807Z-3cd3c21b-2464-42f5-9178-4f8bed6bf571.json",+ "winner": "defender",+ "attacker": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 168+ },+ "defender": {+ "troops": 1446,+ "survivors": 968,+ "losses": 0,+ "injured": 168,+ "lightly_injured": 310,+ "kills": 88+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 3+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 165+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1446,+ "survivors": 968,+ "losses": 0,+ "injured": 168,+ "lightly_injured": 310,+ "kills": 88+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 19,+ "displayed_kills": 4+ },+ "Blastmaster": {+ "triggered": 17,+ "displayed_kills": 1+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_no_lancers_20260927/no_lancers_2.json===================================================================--- testcases/emulator_verified/renee_gwen_no_lancers_20260927/no_lancers_2.json prev run+++ testcases/emulator_verified/renee_gwen_no_lancers_20260927/no_lancers_2.json this run@@ -0,0 +1,154 @@+[+ {+ "test_id": "no_lancers_2",+ "description": "C2 battle report 2734693171422031",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 50,+ "marksman_t6": 50+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 2567+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-27T02:04:09.000Z",+ "randomseed": 1790474650,+ "attacker": 0,+ "defender": 2424,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171422031",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-27T02-04-24.719Z-6e61cd10-b21e-403a-ab66-85db070e2c80.json",+ "winner": "defender",+ "attacker": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 36,+ "lightly_injured": 64,+ "kills": 51+ },+ "defender": {+ "troops": 2567,+ "survivors": 2424,+ "losses": 0,+ "injured": 51,+ "lightly_injured": 92,+ "kills": 36+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 6+ },+ "marksman_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 45+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 2567,+ "survivors": 2424,+ "losses": 0,+ "injured": 51,+ "lightly_injured": 92,+ "kills": 36+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 5,+ "displayed_kills": 1+ },+ "Blastmaster": {+ "triggered": 4,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_no_lancers_20260927/no_lancers_3.json===================================================================--- testcases/emulator_verified/renee_gwen_no_lancers_20260927/no_lancers_3.json prev run+++ testcases/emulator_verified/renee_gwen_no_lancers_20260927/no_lancers_3.json this run@@ -0,0 +1,154 @@+[+ {+ "test_id": "no_lancers_3",+ "description": "C2 battle report 2734693171422073",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 100,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 600+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-27T02:04:54.000Z",+ "randomseed": 1790474695,+ "attacker": 257,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171422073",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-27T02-05-09.781Z-a25aa0a6-5c6c-42de-a559-41ca3943b8ff.json",+ "winner": "attacker",+ "attacker": {+ "troops": 300,+ "survivors": 257,+ "losses": 0,+ "injured": 16,+ "lightly_injured": 27,+ "kills": 210+ },+ "defender": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 16+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 100,+ "survivors": 57,+ "losses": 0,+ "injured": 16,+ "lightly_injured": 27,+ "kills": 24+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 200,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 186+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 16+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 6,+ "displayed_kills": 5+ },+ "Blastmaster": {+ "triggered": 4,+ "displayed_kills": 3+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_no_lancers_20260927/no_lancers_4.json===================================================================--- testcases/emulator_verified/renee_gwen_no_lancers_20260927/no_lancers_4.json prev run+++ testcases/emulator_verified/renee_gwen_no_lancers_20260927/no_lancers_4.json this run@@ -0,0 +1,154 @@+[+ {+ "test_id": "no_lancers_4",+ "description": "C2 battle report 2734693171422164",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 200,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-27T02:05:39.000Z",+ "randomseed": 1790474740,+ "attacker": 183,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171422164",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-27T02-05-54.731Z-ebbe6aef-0ca7-4ea5-8259-ada9eacee89f.json",+ "winner": "attacker",+ "attacker": {+ "troops": 300,+ "survivors": 183,+ "losses": 0,+ "injured": 41,+ "lightly_injured": 76,+ "kills": 350+ },+ "defender": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 41+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 83,+ "losses": 0,+ "injured": 41,+ "lightly_injured": 76,+ "kills": 66+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 100,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 284+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 41+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 16,+ "displayed_kills": 10+ },+ "Blastmaster": {+ "triggered": 9,+ "displayed_kills": 4+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_precision_20260925/gwen_only_1000l_vs_3000l.json===================================================================--- testcases/emulator_verified/renee_gwen_precision_20260925/gwen_only_1000l_vs_3000l.json prev run+++ testcases/emulator_verified/renee_gwen_precision_20260925/gwen_only_1000l_vs_3000l.json this run@@ -0,0 +1,144 @@+[+ {+ "test_id": "gwen_only_1000l_vs_3000l",+ "description": "C2 battle report 2734693171346281",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "lancer_t6": 3000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T10:06:29.000Z",+ "randomseed": 1790330790,+ "attacker": 0,+ "defender": 2086,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171346281",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T10-06-44.984Z-a57688bb-e91a-40b5-812e-c3c28f054519.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 320+ },+ "defender": {+ "troops": 3000,+ "survivors": 2086,+ "losses": 0,+ "injured": 320,+ "lightly_injured": 594,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 320+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 3000,+ "survivors": 2086,+ "losses": 0,+ "injured": 320,+ "lightly_injured": 594,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 4,+ "displayed_kills": 9+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_precision_20260925/renee_gwen_1000l_vs_7800l.json===================================================================--- testcases/emulator_verified/renee_gwen_precision_20260925/renee_gwen_1000l_vs_7800l.json prev run+++ testcases/emulator_verified/renee_gwen_precision_20260925/renee_gwen_1000l_vs_7800l.json this run@@ -0,0 +1,156 @@+[+ {+ "test_id": "renee_gwen_1000l_vs_7800l",+ "description": "C2 battle report 2734693171346231",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 607.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "lancer_t6": 7800+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T10:03:19.000Z",+ "randomseed": 1790330600,+ "attacker": 0,+ "defender": 2518,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171346231",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T10-03-34.975Z-facc20ac-e60b-46f7-93e1-de1c59b44cd7.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 1849+ },+ "defender": {+ "troops": 7800,+ "survivors": 2518,+ "losses": 0,+ "injured": 1849,+ "lightly_injured": 3433,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 1849+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 7800,+ "survivors": 2518,+ "losses": 0,+ "injured": 1849,+ "lightly_injured": 3433,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 6,+ "displayed_kills": 23+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 19,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_precision_20260925/renee_only_1000l_vs_7800l.json===================================================================--- testcases/emulator_verified/renee_gwen_precision_20260925/renee_only_1000l_vs_7800l.json prev run+++ testcases/emulator_verified/renee_gwen_precision_20260925/renee_only_1000l_vs_7800l.json this run@@ -0,0 +1,140 @@+[+ {+ "test_id": "renee_only_1000l_vs_7800l",+ "description": "C2 battle report 2734693171346273",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 607.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "lancer_t6": 7800+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T10:05:02.000Z",+ "randomseed": 1790330703,+ "attacker": 0,+ "defender": 3037,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171346273",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T10-05-17.976Z-bd2634fc-cf60-4ee6-8c7c-f6babfff7ecd.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 1668+ },+ "defender": {+ "troops": 7800,+ "survivors": 3037,+ "losses": 0,+ "injured": 1668,+ "lightly_injured": 3095,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 1668+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 7800,+ "survivors": 3037,+ "losses": 0,+ "injured": 1668,+ "lightly_injured": 3095,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 18,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_single_lines_20260927/only_infantry.json===================================================================--- testcases/emulator_verified/renee_gwen_single_lines_20260927/only_infantry.json prev run+++ testcases/emulator_verified/renee_gwen_single_lines_20260927/only_infantry.json this run@@ -0,0 +1,145 @@+[+ {+ "test_id": "only_infantry",+ "description": "C2 battle report 2734693171424617",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-27T02:37:03.000Z",+ "randomseed": 1790476624,+ "attacker": 0,+ "defender": 807,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171424617",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-27T02-37-18.528Z-fc7a57db-3a7a-4a38-baf0-8dfd06b49069.json",+ "winner": "defender",+ "attacker": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 68+ },+ "defender": {+ "troops": 1000,+ "survivors": 807,+ "losses": 0,+ "injured": 68,+ "lightly_injured": 125,+ "kills": 70+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 68+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 807,+ "losses": 0,+ "injured": 68,+ "lightly_injured": 125,+ "kills": 70+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 12,+ "displayed_kills": 2+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_single_lines_20260927/only_marksman.json===================================================================--- testcases/emulator_verified/renee_gwen_single_lines_20260927/only_marksman.json prev run+++ testcases/emulator_verified/renee_gwen_single_lines_20260927/only_marksman.json this run@@ -0,0 +1,145 @@+[+ {+ "test_id": "only_marksman",+ "description": "C2 battle report 2734693171424687",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-27T02:37:48.000Z",+ "randomseed": 1790476669,+ "attacker": 0,+ "defender": 709,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171424687",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-27T02-38-03.813Z-54044085-80ab-48a3-98ae-2ca585e3c406.json",+ "winner": "defender",+ "attacker": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 102+ },+ "defender": {+ "troops": 1000,+ "survivors": 709,+ "losses": 0,+ "injured": 102,+ "lightly_injured": 189,+ "kills": 70+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 102+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 709,+ "losses": 0,+ "injured": 102,+ "lightly_injured": 189,+ "kills": 70+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 3,+ "displayed_kills": 3+ },+ "Blastmaster": {+ "triggered": 4,+ "displayed_kills": 2+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_t9_probe_20260929/g_1000l_vs_20000t9.json===================================================================--- testcases/emulator_verified/renee_gwen_t9_probe_20260929/g_1000l_vs_20000t9.json prev run+++ testcases/emulator_verified/renee_gwen_t9_probe_20260929/g_1000l_vs_20000t9.json this run@@ -0,0 +1,146 @@+[+ {+ "test_id": "g_1000l_vs_20000t9",+ "description": "C2 battle report 2734693171525691",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 20000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T10:11:07.000Z",+ "randomseed": 1790676668,+ "attacker": 0,+ "defender": 19858,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171525691",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T10-11-23.120Z-4ba489d1-8874-42c0-86e3-11848a2cdc12.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 50+ },+ "defender": {+ "troops": 20000,+ "survivors": 19858,+ "losses": 0,+ "injured": 50,+ "lightly_injured": 92,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 50+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 20000,+ "survivors": 19858,+ "losses": 0,+ "injured": 50,+ "lightly_injured": 92,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 1,+ "displayed_kills": 1+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_t9_probe_20260929/g_60i_1000l_vs_20000t9.json===================================================================--- testcases/emulator_verified/renee_gwen_t9_probe_20260929/g_60i_1000l_vs_20000t9.json prev run+++ testcases/emulator_verified/renee_gwen_t9_probe_20260929/g_60i_1000l_vs_20000t9.json this run@@ -0,0 +1,155 @@+[+ {+ "test_id": "g_60i_1000l_vs_20000t9",+ "description": "C2 battle report 2734693171525906",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 60,+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 20000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T10:25:23.000Z",+ "randomseed": 1790677524,+ "attacker": 0,+ "defender": 19787,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171525906",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T10-25-39.108Z-d2a91b29-0882-4581-97de-82057530a9b4.json",+ "winner": "defender",+ "attacker": {+ "troops": 1060,+ "survivors": 0,+ "losses": 0,+ "injured": 371,+ "lightly_injured": 689,+ "kills": 75+ },+ "defender": {+ "troops": 20000,+ "survivors": 19787,+ "losses": 0,+ "injured": 75,+ "lightly_injured": 138,+ "kills": 371+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 60,+ "survivors": 0,+ "losses": 0,+ "injured": 21,+ "lightly_injured": 39,+ "kills": 1+ },+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 74+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 20000,+ "survivors": 19787,+ "losses": 0,+ "injured": 75,+ "lightly_injured": 138,+ "kills": 371+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 1,+ "displayed_kills": 1+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 2,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_t9_probe_20260929/r_1000l_vs_20000t9.json===================================================================--- testcases/emulator_verified/renee_gwen_t9_probe_20260929/r_1000l_vs_20000t9.json prev run+++ testcases/emulator_verified/renee_gwen_t9_probe_20260929/r_1000l_vs_20000t9.json this run@@ -0,0 +1,142 @@+[+ {+ "test_id": "r_1000l_vs_20000t9",+ "description": "C2 battle report 2734693171525676",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 607.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 20000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T10:10:21.000Z",+ "randomseed": 1790676622,+ "attacker": 0,+ "defender": 18980,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171525676",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T10-10-37.107Z-66f60609-c560-4577-907d-0401d3f64e08.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 357+ },+ "defender": {+ "troops": 20000,+ "survivors": 18980,+ "losses": 0,+ "injured": 357,+ "lightly_injured": 663,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 357+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 20000,+ "survivors": 18980,+ "losses": 0,+ "injured": 357,+ "lightly_injured": 663,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 6,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 4,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_t9_probe_20260929/r_60i_1000l_vs_20000t9.json===================================================================--- testcases/emulator_verified/renee_gwen_t9_probe_20260929/r_60i_1000l_vs_20000t9.json prev run+++ testcases/emulator_verified/renee_gwen_t9_probe_20260929/r_60i_1000l_vs_20000t9.json this run@@ -0,0 +1,151 @@+[+ {+ "test_id": "r_60i_1000l_vs_20000t9",+ "description": "C2 battle report 2734693171525899",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 60,+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 607.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 20000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T10:24:37.000Z",+ "randomseed": 1790677478,+ "attacker": 0,+ "defender": 18729,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171525899",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T10-24-53.111Z-cc396bcd-837b-457b-96d6-7c2bfe3a7a1e.json",+ "winner": "defender",+ "attacker": {+ "troops": 1060,+ "survivors": 0,+ "losses": 0,+ "injured": 371,+ "lightly_injured": 689,+ "kills": 445+ },+ "defender": {+ "troops": 20000,+ "survivors": 18729,+ "losses": 0,+ "injured": 445,+ "lightly_injured": 826,+ "kills": 371+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 60,+ "survivors": 0,+ "losses": 0,+ "injured": 21,+ "lightly_injured": 39,+ "kills": 1+ },+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 444+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 20000,+ "survivors": 18729,+ "losses": 0,+ "injured": 445,+ "lightly_injured": 826,+ "kills": 371+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 7,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 1,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_t9_probe_20260929/rg_1000l_vs_20000t9.json===================================================================--- testcases/emulator_verified/renee_gwen_t9_probe_20260929/rg_1000l_vs_20000t9.json prev run+++ testcases/emulator_verified/renee_gwen_t9_probe_20260929/rg_1000l_vs_20000t9.json this run@@ -0,0 +1,158 @@+[+ {+ "test_id": "rg_1000l_vs_20000t9",+ "description": "C2 battle report 2734693171525646",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 607.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 20000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T10:09:10.000Z",+ "randomseed": 1790676551,+ "attacker": 0,+ "defender": 18899,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171525646",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T10-09-26.158Z-6ec73045-b76a-49a7-93e3-12e4a36d45c2.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 386+ },+ "defender": {+ "troops": 20000,+ "survivors": 18899,+ "losses": 0,+ "injured": 386,+ "lightly_injured": 715,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 386+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 20000,+ "survivors": 18899,+ "losses": 0,+ "injured": 386,+ "lightly_injured": 715,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 2,+ "displayed_kills": 3+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 6,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 4,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_t9_probe_20260929/rg_200i_1000l_vs_20000t9.json===================================================================--- testcases/emulator_verified/renee_gwen_t9_probe_20260929/rg_200i_1000l_vs_20000t9.json prev run+++ testcases/emulator_verified/renee_gwen_t9_probe_20260929/rg_200i_1000l_vs_20000t9.json this run@@ -0,0 +1,167 @@+[+ {+ "test_id": "rg_200i_1000l_vs_20000t9",+ "description": "C2 battle report 2734693171525704",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 200,+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 607.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 20000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T10:13:24.000Z",+ "randomseed": 1790676805,+ "attacker": 0,+ "defender": 18241,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171525704",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T10-13-40.113Z-6e8310a7-e3ea-4e34-b721-de96368f2715.json",+ "winner": "defender",+ "attacker": {+ "troops": 1200,+ "survivors": 0,+ "losses": 0,+ "injured": 420,+ "lightly_injured": 780,+ "kills": 616+ },+ "defender": {+ "troops": 20000,+ "survivors": 18241,+ "losses": 0,+ "injured": 616,+ "lightly_injured": 1143,+ "kills": 420+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 8+ },+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 608+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 20000,+ "survivors": 18241,+ "losses": 0,+ "injured": 616,+ "lightly_injured": 1143,+ "kills": 420+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 2,+ "displayed_kills": 7+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 8,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 4,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_t9_probe_20260929/rg_30i_1000l_vs_20000t9.json===================================================================--- testcases/emulator_verified/renee_gwen_t9_probe_20260929/rg_30i_1000l_vs_20000t9.json prev run+++ testcases/emulator_verified/renee_gwen_t9_probe_20260929/rg_30i_1000l_vs_20000t9.json this run@@ -0,0 +1,167 @@+[+ {+ "test_id": "rg_30i_1000l_vs_20000t9",+ "description": "C2 battle report 2734693171525840",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 30,+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 607.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 20000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T10:21:38.000Z",+ "randomseed": 1790677299,+ "attacker": 0,+ "defender": 18753,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171525840",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T10-21-54.121Z-f0d0ccf9-9ff2-493c-a21f-bf1d413c374d.json",+ "winner": "defender",+ "attacker": {+ "troops": 1030,+ "survivors": 0,+ "losses": 0,+ "injured": 361,+ "lightly_injured": 669,+ "kills": 437+ },+ "defender": {+ "troops": 20000,+ "survivors": 18753,+ "losses": 0,+ "injured": 437,+ "lightly_injured": 810,+ "kills": 361+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 30,+ "survivors": 0,+ "losses": 0,+ "injured": 11,+ "lightly_injured": 19,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 437+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 20000,+ "survivors": 18753,+ "losses": 0,+ "injured": 437,+ "lightly_injured": 810,+ "kills": 361+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 2,+ "displayed_kills": 4+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 6,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 3,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_t9_probe_20260929/rg_400i_1000l_vs_20000t9.json===================================================================--- testcases/emulator_verified/renee_gwen_t9_probe_20260929/rg_400i_1000l_vs_20000t9.json prev run+++ testcases/emulator_verified/renee_gwen_t9_probe_20260929/rg_400i_1000l_vs_20000t9.json this run@@ -0,0 +1,167 @@+[+ {+ "test_id": "rg_400i_1000l_vs_20000t9",+ "description": "C2 battle report 2734693171525878",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 400,+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 607.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 20000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T10:23:09.000Z",+ "randomseed": 1790677390,+ "attacker": 0,+ "defender": 17648,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171525878",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T10-23-25.124Z-c19dc68b-d494-4e3f-bde1-c1faf1e83d7f.json",+ "winner": "defender",+ "attacker": {+ "troops": 1400,+ "survivors": 0,+ "losses": 0,+ "injured": 490,+ "lightly_injured": 910,+ "kills": 824+ },+ "defender": {+ "troops": 20000,+ "survivors": 17648,+ "losses": 0,+ "injured": 824,+ "lightly_injured": 1528,+ "kills": 490+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 26+ },+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 798+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 20000,+ "survivors": 17648,+ "losses": 0,+ "injured": 824,+ "lightly_injured": 1528,+ "kills": 490+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 4,+ "displayed_kills": 9+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 9,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 4,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_gwen_t9_probe_20260929/rg_60i_1000l_vs_20000t9.json===================================================================--- testcases/emulator_verified/renee_gwen_t9_probe_20260929/rg_60i_1000l_vs_20000t9.json prev run+++ testcases/emulator_verified/renee_gwen_t9_probe_20260929/rg_60i_1000l_vs_20000t9.json this run@@ -0,0 +1,167 @@+[+ {+ "test_id": "rg_60i_1000l_vs_20000t9",+ "description": "C2 battle report 2734693171525850",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 60,+ "lancer_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 607.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 435.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t9": 20000+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T10:22:24.000Z",+ "randomseed": 1790677345,+ "attacker": 0,+ "defender": 18616,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171525850",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T10-22-40.107Z-433709f2-68de-479f-9cc9-54856267f142.json",+ "winner": "defender",+ "attacker": {+ "troops": 1060,+ "survivors": 0,+ "losses": 0,+ "injured": 371,+ "lightly_injured": 689,+ "kills": 485+ },+ "defender": {+ "troops": 20000,+ "survivors": 18616,+ "losses": 0,+ "injured": 485,+ "lightly_injured": 899,+ "kills": 371+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 60,+ "survivors": 0,+ "losses": 0,+ "injured": 21,+ "lightly_injured": 39,+ "kills": 1+ },+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 484+ }+ },+ "defender": {+ "lancer_t9": {+ "troops": 20000,+ "survivors": 18616,+ "losses": 0,+ "injured": 485,+ "lightly_injured": 899,+ "kills": 371+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 2,+ "displayed_kills": 4+ },+ "Blastmaster": {+ "triggered": null,+ "displayed_kills": null+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 7,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Troop skills": {+ "Ambusher": {+ "triggered": 4,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_mixed_partners_20260929/renee_jasser_balanced.json===================================================================--- testcases/emulator_verified/renee_mixed_partners_20260929/renee_jasser_balanced.json prev run+++ testcases/emulator_verified/renee_mixed_partners_20260929/renee_jasser_balanced.json this run@@ -0,0 +1,175 @@+[+ {+ "test_id": "renee_jasser_balanced",+ "description": "C2 battle report 2734693171520002",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 150,+ "lancer_t6": 200,+ "marksman_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "infantry_t6": 200,+ "lancer_t6": 500,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T04:33:59.000Z",+ "randomseed": 1790656440,+ "attacker": 0,+ "defender": 432,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171520002",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T04-34-24.156Z-9b84bce7-870a-4e7c-8c36-7e6fdaab5913.json",+ "winner": "defender",+ "attacker": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 176,+ "lightly_injured": 324,+ "kills": 199+ },+ "defender": {+ "troops": 1000,+ "survivors": 432,+ "losses": 0,+ "injured": 199,+ "lightly_injured": 369,+ "kills": 176+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 2+ },+ "lancer_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 110+ },+ "marksman_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 87+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 4+ },+ "lancer_t6": {+ "troops": 500,+ "survivors": 132,+ "losses": 0,+ "injured": 129,+ "lightly_injured": 239,+ "kills": 76+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 300,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 96+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 13,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_mixed_partners_20260929/renee_jasser_lancer_heavy.json===================================================================--- testcases/emulator_verified/renee_mixed_partners_20260929/renee_jasser_lancer_heavy.json prev run+++ testcases/emulator_verified/renee_mixed_partners_20260929/renee_jasser_lancer_heavy.json this run@@ -0,0 +1,175 @@+[+ {+ "test_id": "renee_jasser_lancer_heavy",+ "description": "C2 battle report 2734693171519840",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Jasser": {+ "skill_1": 2,+ "skill_2": 4+ }+ },+ "troops": {+ "infantry_t6": 50,+ "lancer_t6": 300,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "infantry_t6": 300,+ "lancer_t6": 600,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T04:29:43.000Z",+ "randomseed": 1790656184,+ "attacker": 0,+ "defender": 820,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171519840",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T04-30-08.194Z-a6e4ffdc-f86b-4f05-9ad3-2890b91bf95a.json",+ "winner": "defender",+ "attacker": {+ "troops": 450,+ "survivors": 0,+ "losses": 0,+ "injured": 158,+ "lightly_injured": 292,+ "kills": 98+ },+ "defender": {+ "troops": 1100,+ "survivors": 820,+ "losses": 0,+ "injured": 98,+ "lightly_injured": 182,+ "kills": 158+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 64+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 34+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 300,+ "survivors": 20,+ "losses": 0,+ "injured": 98,+ "lightly_injured": 182,+ "kills": 12+ },+ "lancer_t6": {+ "troops": 600,+ "survivors": 600,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 84+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 200,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 62+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 11,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_mixed_partners_20260929/renee_seoyoon_balanced.json===================================================================--- testcases/emulator_verified/renee_mixed_partners_20260929/renee_seoyoon_balanced.json prev run+++ testcases/emulator_verified/renee_mixed_partners_20260929/renee_seoyoon_balanced.json this run@@ -0,0 +1,175 @@+[+ {+ "test_id": "renee_seoyoon_balanced",+ "description": "C2 battle report 2734693171520041",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Seo-yoon": {+ "skill_1": 4,+ "skill_2": 3+ }+ },+ "troops": {+ "infantry_t6": 150,+ "lancer_t6": 200,+ "marksman_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "infantry_t6": 200,+ "lancer_t6": 500,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T04:36:07.000Z",+ "randomseed": 1790656568,+ "attacker": 0,+ "defender": 195,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171520041",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T04-36-32.181Z-ce0809fa-972d-4e6b-a14c-ec190b34a3f3.json",+ "winner": "defender",+ "attacker": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 176,+ "lightly_injured": 324,+ "kills": 282+ },+ "defender": {+ "troops": 1000,+ "survivors": 195,+ "losses": 0,+ "injured": 282,+ "lightly_injured": 523,+ "kills": 176+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 3+ },+ "lancer_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 149+ },+ "marksman_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 130+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 3+ },+ "lancer_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 51+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 195,+ "losses": 0,+ "injured": 37,+ "lightly_injured": 68,+ "kills": 122+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 15,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_mixed_partners_20260929/renee_seoyoon_lancer_heavy.json===================================================================--- testcases/emulator_verified/renee_mixed_partners_20260929/renee_seoyoon_lancer_heavy.json prev run+++ testcases/emulator_verified/renee_mixed_partners_20260929/renee_seoyoon_lancer_heavy.json this run@@ -0,0 +1,175 @@+[+ {+ "test_id": "renee_seoyoon_lancer_heavy",+ "description": "C2 battle report 2734693171519981",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Seo-yoon": {+ "skill_1": 4,+ "skill_2": 3+ }+ },+ "troops": {+ "infantry_t6": 50,+ "lancer_t6": 300,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 297.4,+ "defense": 286.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "infantry_t6": 300,+ "lancer_t6": 600,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T04:31:51.000Z",+ "randomseed": 1790656312,+ "attacker": 0,+ "defender": 791,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171519981",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T04-32-16.147Z-de5932bd-6442-4d82-a8fb-5c95fc39c57c.json",+ "winner": "defender",+ "attacker": {+ "troops": 450,+ "survivors": 0,+ "losses": 0,+ "injured": 158,+ "lightly_injured": 292,+ "kills": 109+ },+ "defender": {+ "troops": 1100,+ "survivors": 791,+ "losses": 0,+ "injured": 109,+ "lightly_injured": 200,+ "kills": 158+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 71+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 38+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 11+ },+ "lancer_t6": {+ "troops": 600,+ "survivors": 591,+ "losses": 0,+ "injured": 4,+ "lightly_injured": 5,+ "kills": 86+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 200,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 61+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 11,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_mixed_partners_20260929/renee_sergey_balanced.json===================================================================--- testcases/emulator_verified/renee_mixed_partners_20260929/renee_sergey_balanced.json prev run+++ testcases/emulator_verified/renee_mixed_partners_20260929/renee_sergey_balanced.json this run@@ -0,0 +1,175 @@+[+ {+ "test_id": "renee_sergey_balanced",+ "description": "C2 battle report 2734693171520015",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Sergey": {+ "skill_1": 2,+ "skill_2": 2+ }+ },+ "troops": {+ "infantry_t6": 150,+ "lancer_t6": 200,+ "marksman_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 346.14,+ "defense": 338.69,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "infantry_t6": 200,+ "lancer_t6": 500,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T04:35:03.000Z",+ "randomseed": 1790656504,+ "attacker": 0,+ "defender": 161,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171520015",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T04-35-28.159Z-6921bd5b-83ea-42c9-b7be-380dbab4abb3.json",+ "winner": "defender",+ "attacker": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 176,+ "lightly_injured": 324,+ "kills": 294+ },+ "defender": {+ "troops": 1000,+ "survivors": 161,+ "losses": 0,+ "injured": 294,+ "lightly_injured": 545,+ "kills": 176+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 5+ },+ "lancer_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 172+ },+ "marksman_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 117+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 2+ },+ "lancer_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 46+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 161,+ "losses": 0,+ "injured": 49,+ "lightly_injured": 90,+ "kills": 128+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 20,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_mixed_partners_20260929/renee_sergey_lancer_heavy.json===================================================================--- testcases/emulator_verified/renee_mixed_partners_20260929/renee_sergey_lancer_heavy.json prev run+++ testcases/emulator_verified/renee_mixed_partners_20260929/renee_sergey_lancer_heavy.json this run@@ -0,0 +1,175 @@+[+ {+ "test_id": "renee_sergey_lancer_heavy",+ "description": "C2 battle report 2734693171519930",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Sergey": {+ "skill_1": 2,+ "skill_2": 2+ }+ },+ "troops": {+ "infantry_t6": 50,+ "lancer_t6": 300,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 346.14,+ "defense": 338.69,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "infantry_t6": 300,+ "lancer_t6": 600,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T04:30:47.000Z",+ "randomseed": 1790656248,+ "attacker": 0,+ "defender": 788,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171519930",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T04-31-12.159Z-3be22590-39cd-48f1-9d8e-2c14f97b3c7d.json",+ "winner": "defender",+ "attacker": {+ "troops": 450,+ "survivors": 0,+ "losses": 0,+ "injured": 158,+ "lightly_injured": 292,+ "kills": 110+ },+ "defender": {+ "troops": 1100,+ "survivors": 788,+ "losses": 0,+ "injured": 110,+ "lightly_injured": 202,+ "kills": 158+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 77+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 33+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 10+ },+ "lancer_t6": {+ "troops": 600,+ "survivors": 588,+ "losses": 0,+ "injured": 5,+ "lightly_injured": 7,+ "kills": 85+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 200,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 63+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 14,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_mixed_partners_20260929/renee_solo_balanced.json===================================================================--- testcases/emulator_verified/renee_mixed_partners_20260929/renee_solo_balanced.json prev run+++ testcases/emulator_verified/renee_mixed_partners_20260929/renee_solo_balanced.json this run@@ -0,0 +1,171 @@+[+ {+ "test_id": "renee_solo_balanced",+ "description": "C2 battle report 2734693171519985",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 150,+ "lancer_t6": 200,+ "marksman_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "infantry_t6": 200,+ "lancer_t6": 500,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T04:32:55.000Z",+ "randomseed": 1790656376,+ "attacker": 0,+ "defender": 584,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171519985",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T04-33-20.146Z-49f49567-2744-4c61-a38b-8f73ecf36b20.json",+ "winner": "defender",+ "attacker": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 176,+ "lightly_injured": 324,+ "kills": 146+ },+ "defender": {+ "troops": 1000,+ "survivors": 584,+ "losses": 0,+ "injured": 146,+ "lightly_injured": 270,+ "kills": 176+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 2+ },+ "lancer_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 86+ },+ "marksman_t6": {+ "troops": 150,+ "survivors": 0,+ "losses": 0,+ "injured": 53,+ "lightly_injured": 97,+ "kills": 58+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 5+ },+ "lancer_t6": {+ "troops": 500,+ "survivors": 284,+ "losses": 0,+ "injured": 76,+ "lightly_injured": 140,+ "kills": 82+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 300,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 89+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 12,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_mixed_partners_20260929/renee_solo_lancer_heavy.json===================================================================--- testcases/emulator_verified/renee_mixed_partners_20260929/renee_solo_lancer_heavy.json prev run+++ testcases/emulator_verified/renee_mixed_partners_20260929/renee_solo_lancer_heavy.json this run@@ -0,0 +1,171 @@+[+ {+ "test_id": "renee_solo_lancer_heavy",+ "description": "C2 battle report 2734693171519814",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 50,+ "lancer_t6": 300,+ "marksman_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "infantry_t6": 300,+ "lancer_t6": 600,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-29T04:28:39.000Z",+ "randomseed": 1790656120,+ "attacker": 0,+ "defender": 859,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171519814",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-29T04-29-04.185Z-dfed11fd-ef2d-4b2d-9d72-019d22103658.json",+ "winner": "defender",+ "attacker": {+ "troops": 450,+ "survivors": 0,+ "losses": 0,+ "injured": 158,+ "lightly_injured": 292,+ "kills": 85+ },+ "defender": {+ "troops": 1100,+ "survivors": 859,+ "losses": 0,+ "injured": 85,+ "lightly_injured": 156,+ "kills": 158+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 0+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 61+ },+ "marksman_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 24+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 300,+ "survivors": 59,+ "losses": 0,+ "injured": 85,+ "lightly_injured": 156,+ "kills": 14+ },+ "lancer_t6": {+ "troops": 600,+ "survivors": 600,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 86+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 200,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 58+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 11,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_shield_saturation_20260926/renee_100l_vs_gatot_100i.json===================================================================--- testcases/emulator_verified/renee_shield_saturation_20260926/renee_100l_vs_gatot_100i.json prev run+++ testcases/emulator_verified/renee_shield_saturation_20260926/renee_100l_vs_gatot_100i.json this run@@ -0,0 +1,149 @@+[+ {+ "test_id": "renee_100l_vs_gatot_100i",+ "description": "C2 battle report 2734693171383452",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t9": 100+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T08:18:48.000Z",+ "randomseed": 1790410729,+ "attacker": 0,+ "defender": 91,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171383452",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T08-19-05.115Z-a02a4078-c115-4800-9731-f6cfd892c3af.json",+ "winner": "defender",+ "attacker": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 0+ },+ "defender": {+ "troops": 100,+ "survivors": 91,+ "losses": 0,+ "injured": 4,+ "lightly_injured": 5,+ "kills": 35+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 0+ }+ },+ "defender": {+ "infantry_t9": {+ "troops": 100,+ "survivors": 91,+ "losses": 0,+ "injured": 4,+ "lightly_injured": 5,+ "kills": 35+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 28,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Gatot": {+ "King's Bestowal": {+ "triggered": 56,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_shield_saturation_20260926/renee_100l_vs_gatot_50i.json===================================================================--- testcases/emulator_verified/renee_shield_saturation_20260926/renee_100l_vs_gatot_50i.json prev run+++ testcases/emulator_verified/renee_shield_saturation_20260926/renee_100l_vs_gatot_50i.json this run@@ -0,0 +1,149 @@+[+ {+ "test_id": "renee_100l_vs_gatot_50i",+ "description": "C2 battle report 2734693171383435",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 100+ },+ "stats": {+ "infantry": {+ "attack": 299.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 607.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 283.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t9": 50+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T08:17:04.000Z",+ "randomseed": 1790410625,+ "attacker": 0,+ "defender": 37,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171383435",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T08-17-21.127Z-bb32ec56-861a-4270-8a5d-b3dcc22ea773.json",+ "winner": "defender",+ "attacker": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 0+ },+ "defender": {+ "troops": 50,+ "survivors": 37,+ "losses": 0,+ "injured": 5,+ "lightly_injured": 8,+ "kills": 35+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 100,+ "survivors": 0,+ "losses": 0,+ "injured": 35,+ "lightly_injured": 65,+ "kills": 0+ }+ },+ "defender": {+ "infantry_t9": {+ "troops": 50,+ "survivors": 37,+ "losses": 0,+ "injured": 5,+ "lightly_injured": 8,+ "kills": 35+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 59,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Gatot": {+ "King's Bestowal": {+ "triggered": 118,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_stun_20260925/renee_300l_vs_sonya_250l.json===================================================================--- testcases/emulator_verified/renee_stun_20260925/renee_300l_vs_sonya_250l.json prev run+++ testcases/emulator_verified/renee_stun_20260925/renee_300l_vs_sonya_250l.json this run@@ -0,0 +1,153 @@+[+ {+ "test_id": "renee_300l_vs_sonya_250l",+ "description": "C2 battle report 2734693171360925",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 250+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 534.96,+ "defense": 534.21,+ "lethality": 323.16,+ "health": 285.53+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T17:08:58.000Z",+ "randomseed": 1790356139,+ "attacker": 61,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171360925",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T17-09-23.230Z-a12aa5a9-8dae-49eb-88c5-9cdce4817024.json",+ "winner": "attacker",+ "attacker": {+ "troops": 300,+ "survivors": 61,+ "losses": 0,+ "injured": 84,+ "lightly_injured": 155,+ "kills": 88+ },+ "defender": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 84+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 300,+ "survivors": 61,+ "losses": 0,+ "injured": 84,+ "lightly_injured": 155,+ "kills": 88+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 84+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 15,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 15,+ "displayed_kills": 4+ },+ "Torrential Impact": {+ "triggered": 6,+ "displayed_kills": 6+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_stun_20260925/renee_400l_vs_sonya_400l.json===================================================================--- testcases/emulator_verified/renee_stun_20260925/renee_400l_vs_sonya_400l.json prev run+++ testcases/emulator_verified/renee_stun_20260925/renee_400l_vs_sonya_400l.json this run@@ -0,0 +1,153 @@+[+ {+ "test_id": "renee_400l_vs_sonya_400l",+ "description": "C2 battle report 2734693171360981",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 400+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 400+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 534.96,+ "defense": 534.21,+ "lethality": 323.16,+ "health": 285.53+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T17:11:58.000Z",+ "randomseed": 1790356319,+ "attacker": 0,+ "defender": 106,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171360981",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T17-12-23.230Z-aac76978-f650-41e7-b7c7-fd782808d75f.json",+ "winner": "defender",+ "attacker": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 103+ },+ "defender": {+ "troops": 400,+ "survivors": 106,+ "losses": 0,+ "injured": 103,+ "lightly_injured": 191,+ "kills": 140+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 400,+ "survivors": 0,+ "losses": 0,+ "injured": 140,+ "lightly_injured": 260,+ "kills": 103+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 400,+ "survivors": 106,+ "losses": 0,+ "injured": 103,+ "lightly_injured": 191,+ "kills": 140+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 13,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 13,+ "displayed_kills": 8+ },+ "Torrential Impact": {+ "triggered": 5,+ "displayed_kills": 10+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_turn_boundary_20260927/calibration_renee.json===================================================================--- testcases/emulator_verified/renee_turn_boundary_20260927/calibration_renee.json prev run+++ testcases/emulator_verified/renee_turn_boundary_20260927/calibration_renee.json this run@@ -0,0 +1,153 @@+[+ {+ "test_id": "calibration_renee",+ "description": "C2 battle report 2734693171417030",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 200,+ "lancer_t6": 300,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 1500+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T23:40:10.000Z",+ "randomseed": 1790466011,+ "attacker": 733,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171417030",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T23-40-25.813Z-f374f77f-22b5-46b1-8f29-118cfd93ca6a.json",+ "winner": "attacker",+ "attacker": {+ "troops": 800,+ "survivors": 733,+ "losses": 0,+ "injured": 24,+ "lightly_injured": 43,+ "kills": 525+ },+ "defender": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 24+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 133,+ "losses": 0,+ "injured": 24,+ "lightly_injured": 43,+ "kills": 32+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 300,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 315+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 300,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 178+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 24+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 17,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_turn_boundary_20260927/calibration_renee_gwen.json===================================================================--- testcases/emulator_verified/renee_turn_boundary_20260927/calibration_renee_gwen.json prev run+++ testcases/emulator_verified/renee_turn_boundary_20260927/calibration_renee_gwen.json this run@@ -0,0 +1,169 @@+[+ {+ "test_id": "calibration_renee_gwen",+ "description": "C2 battle report 2734693171416967",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 200,+ "lancer_t6": 300,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 1500+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T23:37:58.000Z",+ "randomseed": 1790465879,+ "attacker": 745,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171416967",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T23-38-13.909Z-e8c82022-fcf3-4823-b9d7-059a6c284b15.json",+ "winner": "attacker",+ "attacker": {+ "troops": 800,+ "survivors": 745,+ "losses": 0,+ "injured": 20,+ "lightly_injured": 35,+ "kills": 525+ },+ "defender": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 20+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 200,+ "survivors": 145,+ "losses": 0,+ "injured": 20,+ "lightly_injured": 35,+ "kills": 28+ },+ "lancer_t6": {+ "troops": 300,+ "survivors": 300,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 274+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 300,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 223+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1500,+ "survivors": 0,+ "losses": 0,+ "injured": 525,+ "lightly_injured": 975,+ "kills": 20+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 12,+ "displayed_kills": 8+ },+ "Blastmaster": {+ "triggered": 5,+ "displayed_kills": 3+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 14,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_turn_boundary_20260927/combined_infantry_probe.json===================================================================--- testcases/emulator_verified/renee_turn_boundary_20260927/combined_infantry_probe.json prev run+++ testcases/emulator_verified/renee_turn_boundary_20260927/combined_infantry_probe.json this run@@ -0,0 +1,258 @@+[+ {+ "test_id": "combined_infantry_probe",+ "description": "C2 battle report 2734693171417101",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 50,+ "lancer_t6": 50,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 1446+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T23:47:07.000Z",+ "randomseed": 1790466428,+ "attacker": 8,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171417101",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T23-47-22.846Z-da3fd037-94b2-485d-90b3-e566a3d549f1.json",+ "winner": "attacker",+ "attacker": {+ "troops": 300,+ "survivors": 8,+ "losses": 0,+ "injured": 104,+ "lightly_injured": 188,+ "kills": 507+ },+ "defender": {+ "troops": 1446,+ "survivors": 0,+ "losses": 0,+ "injured": 507,+ "lightly_injured": 939,+ "kills": 104+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 6+ },+ "lancer_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 105+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 8,+ "losses": 0,+ "injured": 68,+ "lightly_injured": 124,+ "kills": 396+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1446,+ "survivors": 0,+ "losses": 0,+ "injured": 507,+ "lightly_injured": 939,+ "kills": 104+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 42,+ "displayed_kills": 10+ },+ "Blastmaster": {+ "triggered": 34,+ "displayed_kills": 6+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 86,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-26T23:47:50.000Z",+ "randomseed": 1790466471,+ "attacker": 8,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171417107",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T23-48-05.900Z-1c0a6586-c5f6-494c-8778-48bd60da36bd.json",+ "winner": "attacker",+ "attacker": {+ "troops": 300,+ "survivors": 8,+ "losses": 0,+ "injured": 104,+ "lightly_injured": 188,+ "kills": 507+ },+ "defender": {+ "troops": 1446,+ "survivors": 0,+ "losses": 0,+ "injured": 507,+ "lightly_injured": 939,+ "kills": 104+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 6+ },+ "lancer_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 105+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 8,+ "losses": 0,+ "injured": 68,+ "lightly_injured": 124,+ "kills": 396+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1446,+ "survivors": 0,+ "losses": 0,+ "injured": 507,+ "lightly_injured": 939,+ "kills": 104+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 42,+ "displayed_kills": 10+ },+ "Blastmaster": {+ "triggered": 34,+ "displayed_kills": 6+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 86,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_turn_boundary_20260927/combined_lancer_probe.json===================================================================--- testcases/emulator_verified/renee_turn_boundary_20260927/combined_lancer_probe.json prev run+++ testcases/emulator_verified/renee_turn_boundary_20260927/combined_lancer_probe.json this run@@ -0,0 +1,258 @@+[+ {+ "test_id": "combined_lancer_probe",+ "description": "C2 battle report 2734693171417130",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 3,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 50,+ "lancer_t6": 200,+ "marksman_t6": 50+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 439.82,+ "defense": 440.82,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "lancer_t6": 2567+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T23:50:08.000Z",+ "randomseed": 1790466609,+ "attacker": 26,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171417130",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T23-50-23.840Z-b5a42875-03e4-4680-9527-2d6efa8d2458.json",+ "winner": "attacker",+ "attacker": {+ "troops": 300,+ "survivors": 26,+ "losses": 0,+ "injured": 97,+ "lightly_injured": 177,+ "kills": 899+ },+ "defender": {+ "troops": 2567,+ "survivors": 0,+ "losses": 0,+ "injured": 899,+ "lightly_injured": 1668,+ "kills": 97+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 7+ },+ "lancer_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 538+ },+ "marksman_t6": {+ "troops": 50,+ "survivors": 26,+ "losses": 0,+ "injured": 9,+ "lightly_injured": 15,+ "kills": 354+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 2567,+ "survivors": 0,+ "losses": 0,+ "injured": 899,+ "lightly_injured": 1668,+ "kills": 97+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 17,+ "displayed_kills": 14+ },+ "Blastmaster": {+ "triggered": 11,+ "displayed_kills": 4+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 28,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-26T23:50:51.000Z",+ "randomseed": 1790466652,+ "attacker": 26,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171417133",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T23-51-06.889Z-7a07d930-ece4-4475-b142-d955f93e3b16.json",+ "winner": "attacker",+ "attacker": {+ "troops": 300,+ "survivors": 26,+ "losses": 0,+ "injured": 97,+ "lightly_injured": 177,+ "kills": 899+ },+ "defender": {+ "troops": 2567,+ "survivors": 0,+ "losses": 0,+ "injured": 899,+ "lightly_injured": 1668,+ "kills": 97+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 7+ },+ "lancer_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 538+ },+ "marksman_t6": {+ "troops": 50,+ "survivors": 26,+ "losses": 0,+ "injured": 9,+ "lightly_injured": 15,+ "kills": 354+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 2567,+ "survivors": 0,+ "losses": 0,+ "injured": 899,+ "lightly_injured": 1668,+ "kills": 97+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 17,+ "displayed_kills": 14+ },+ "Blastmaster": {+ "triggered": 11,+ "displayed_kills": 4+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 28,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/renee_turn_boundary_20260927/pure_renee_matched_control.json===================================================================--- testcases/emulator_verified/renee_turn_boundary_20260927/pure_renee_matched_control.json prev run+++ testcases/emulator_verified/renee_turn_boundary_20260927/pure_renee_matched_control.json this run@@ -0,0 +1,232 @@+[+ {+ "test_id": "pure_renee_matched_control",+ "description": "C2 battle report 2734693171417109",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Renee": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 50,+ "lancer_t6": 50,+ "marksman_t6": 200+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 612.83,+ "defense": 612.08,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "infantry_t6": 1446+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-26T23:48:38.000Z",+ "randomseed": 1790466519,+ "attacker": 0,+ "defender": 654,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171417109",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T23-48-53.831Z-18cabd46-c439-4e3b-8f82-c9292cc19b32.json",+ "winner": "defender",+ "attacker": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 106,+ "lightly_injured": 194,+ "kills": 278+ },+ "defender": {+ "troops": 1446,+ "survivors": 654,+ "losses": 0,+ "injured": 278,+ "lightly_injured": 514,+ "kills": 106+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 4+ },+ "lancer_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 96+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 178+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1446,+ "survivors": 654,+ "losses": 0,+ "injured": 278,+ "lightly_injured": 514,+ "kills": 106+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 47,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ },+ {+ "timestamp": "2026-09-26T23:49:21.000Z",+ "randomseed": 1790466562,+ "attacker": 0,+ "defender": 654,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171417127",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-26T23-49-36.907Z-c2a204e3-8e49-458c-89a0-aef6c1e8d615.json",+ "winner": "defender",+ "attacker": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 106,+ "lightly_injured": 194,+ "kills": 278+ },+ "defender": {+ "troops": 1446,+ "survivors": 654,+ "losses": 0,+ "injured": 278,+ "lightly_injured": 514,+ "kills": 106+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 4+ },+ "lancer_t6": {+ "troops": 50,+ "survivors": 0,+ "losses": 0,+ "injured": 18,+ "lightly_injured": 32,+ "kills": 96+ },+ "marksman_t6": {+ "troops": 200,+ "survivors": 0,+ "losses": 0,+ "injured": 70,+ "lightly_injured": 130,+ "kills": 178+ }+ },+ "defender": {+ "infantry_t6": {+ "troops": 1446,+ "survivors": 654,+ "losses": 0,+ "injured": 278,+ "lightly_injured": 514,+ "kills": 106+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 47,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/scheduled_skill_stun_20260925/sonya_150l_vs_hendrik_250m.json===================================================================--- testcases/emulator_verified/scheduled_skill_stun_20260925/sonya_150l_vs_hendrik_250m.json prev run+++ testcases/emulator_verified/scheduled_skill_stun_20260925/sonya_150l_vs_hendrik_250m.json this run@@ -0,0 +1,157 @@+[+ {+ "test_id": "sonya_150l_vs_hendrik_250m",+ "description": "C2 battle report 2734693171359198",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 534.96,+ "defense": 534.21,+ "lethality": 323.16,+ "health": 285.53+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Hendrik": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "marksman_t6": 250+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 479,+ "defense": 467.8,+ "lethality": 244.2,+ "health": 221.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T16:24:38.000Z",+ "randomseed": 1790353479,+ "attacker": 12,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171359198",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T16-24-54.205Z-967ecf59-8ca0-4f97-b173-4a75335917d8.json",+ "winner": "attacker",+ "attacker": {+ "troops": 150,+ "survivors": 12,+ "losses": 0,+ "injured": 49,+ "lightly_injured": 89,+ "kills": 88+ },+ "defender": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 49+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 150,+ "survivors": 12,+ "losses": 0,+ "injured": 49,+ "lightly_injured": 89,+ "kills": 88+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 250,+ "survivors": 0,+ "losses": 0,+ "injured": 88,+ "lightly_injured": 162,+ "kills": 49+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 18,+ "displayed_kills": 5+ },+ "Torrential Impact": {+ "triggered": 7,+ "displayed_kills": 6+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 9,+ "displayed_kills": 4+ },+ "Armor of Barnacles": {+ "triggered": 9,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/scheduled_skill_stun_20260925/sonya_600l_vs_hendrik_1200m.json===================================================================--- testcases/emulator_verified/scheduled_skill_stun_20260925/sonya_600l_vs_hendrik_1200m.json prev run+++ testcases/emulator_verified/scheduled_skill_stun_20260925/sonya_600l_vs_hendrik_1200m.json this run@@ -0,0 +1,157 @@+[+ {+ "test_id": "sonya_600l_vs_hendrik_1200m",+ "description": "C2 battle report 2734693171358881",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 600+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 534.96,+ "defense": 534.21,+ "lethality": 323.16,+ "health": 285.53+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Hendrik": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "marksman_t6": 1200+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 479,+ "defense": 467.8,+ "lethality": 244.2,+ "health": 221.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T16:21:53.000Z",+ "randomseed": 1790353314,+ "attacker": 0,+ "defender": 422,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171358881",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T16-22-09.173Z-3fc45c38-73c6-4820-8615-efe4f2a86303.json",+ "winner": "defender",+ "attacker": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 273+ },+ "defender": {+ "troops": 1200,+ "survivors": 422,+ "losses": 0,+ "injured": 273,+ "lightly_injured": 505,+ "kills": 210+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 600,+ "survivors": 0,+ "losses": 0,+ "injured": 210,+ "lightly_injured": 390,+ "kills": 273+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1200,+ "survivors": 422,+ "losses": 0,+ "injured": 273,+ "lightly_injured": 505,+ "kills": 210+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 14,+ "displayed_kills": 16+ },+ "Torrential Impact": {+ "triggered": 5,+ "displayed_kills": 19+ }+ }+ },+ "defender": {+ "Hendrik": {+ "Dagon's Heir": {+ "triggered": 7,+ "displayed_kills": 14+ },+ "Armor of Barnacles": {+ "triggered": 7,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/scheduled_skill_stun_20260925/wayne_500i_vs_sonya_150l.json===================================================================--- testcases/emulator_verified/scheduled_skill_stun_20260925/wayne_500i_vs_sonya_150l.json prev run+++ testcases/emulator_verified/scheduled_skill_stun_20260925/wayne_500i_vs_sonya_150l.json this run@@ -0,0 +1,489 @@+[+ {+ "test_id": "wayne_500i_vs_sonya_150l",+ "description": "C2 battle report 2734693171359275",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Wayne": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "infantry_t6": 500+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 402.68,+ "defense": 391.48,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {+ "Sonya": {+ "skill_1": 1,+ "skill_2": 1,+ "skill_3": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 150+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 534.96,+ "defense": 534.21,+ "lethality": 323.16,+ "health": 285.53+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T16:26:01.000Z",+ "randomseed": 1790353562,+ "attacker": 0,+ "defender": 35,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171359275",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T16-26-26.210Z-6e6e18e3-e1e3-4372-a8a5-bad051a511d3.json",+ "winner": "defender",+ "attacker": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 41+ },+ "defender": {+ "troops": 150,+ "survivors": 35,+ "losses": 0,+ "injured": 41,+ "lightly_injured": 74,+ "kills": 175+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 41+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 150,+ "survivors": 35,+ "losses": 0,+ "injured": 41,+ "lightly_injured": 74,+ "kills": 175+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Fleet": {+ "triggered": 15,+ "displayed_kills": 3+ },+ "Thunder Strike": {+ "triggered": 29,+ "displayed_kills": 4+ },+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 72,+ "displayed_kills": 9+ },+ "Torrential Impact": {+ "triggered": 28,+ "displayed_kills": 15+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-25T16:27:05.000Z",+ "randomseed": 1790353626,+ "attacker": 0,+ "defender": 37,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171359302",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T16-27-30.186Z-a5ce9c2f-d09b-4bae-b1f8-9181e56bbffe.json",+ "winner": "defender",+ "attacker": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 40+ },+ "defender": {+ "troops": 150,+ "survivors": 37,+ "losses": 0,+ "injured": 40,+ "lightly_injured": 73,+ "kills": 175+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 40+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 150,+ "survivors": 37,+ "losses": 0,+ "injured": 40,+ "lightly_injured": 73,+ "kills": 175+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Fleet": {+ "triggered": 13,+ "displayed_kills": 4+ },+ "Thunder Strike": {+ "triggered": 28,+ "displayed_kills": 3+ },+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 71,+ "displayed_kills": 12+ },+ "Torrential Impact": {+ "triggered": 28,+ "displayed_kills": 13+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-25T16:28:09.000Z",+ "randomseed": 1790353690,+ "attacker": 0,+ "defender": 26,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171359420",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T16-28-34.173Z-ea7cc5d2-56a8-4599-9b78-dbc4bbe5451c.json",+ "winner": "defender",+ "attacker": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 44+ },+ "defender": {+ "troops": 150,+ "survivors": 26,+ "losses": 0,+ "injured": 44,+ "lightly_injured": 80,+ "kills": 175+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 44+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 150,+ "survivors": 26,+ "losses": 0,+ "injured": 44,+ "lightly_injured": 80,+ "kills": 175+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Fleet": {+ "triggered": 23,+ "displayed_kills": 5+ },+ "Thunder Strike": {+ "triggered": 30,+ "displayed_kills": 4+ },+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 75,+ "displayed_kills": 10+ },+ "Torrential Impact": {+ "triggered": 30,+ "displayed_kills": 14+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-25T16:29:13.000Z",+ "randomseed": 1790353754,+ "attacker": 0,+ "defender": 30,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171359563",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T16-29-38.163Z-ef2133e3-2d47-4d92-8834-66962db4f042.json",+ "winner": "defender",+ "attacker": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 42+ },+ "defender": {+ "troops": 150,+ "survivors": 30,+ "losses": 0,+ "injured": 42,+ "lightly_injured": 78,+ "kills": 175+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 42+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 150,+ "survivors": 30,+ "losses": 0,+ "injured": 42,+ "lightly_injured": 78,+ "kills": 175+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Fleet": {+ "triggered": 19,+ "displayed_kills": 4+ },+ "Thunder Strike": {+ "triggered": 29,+ "displayed_kills": 4+ },+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 73,+ "displayed_kills": 13+ },+ "Torrential Impact": {+ "triggered": 29,+ "displayed_kills": 14+ }+ }+ }+ }+ }+ },+ {+ "timestamp": "2026-09-25T16:30:17.000Z",+ "randomseed": 1790353818,+ "attacker": 0,+ "defender": 43,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171359749",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T16-30-42.172Z-b7aa6a22-1d94-4009-b48b-fc9f0a6ee572.json",+ "winner": "defender",+ "attacker": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 38+ },+ "defender": {+ "troops": 150,+ "survivors": 43,+ "losses": 0,+ "injured": 38,+ "lightly_injured": 69,+ "kills": 175+ },+ "troop_details": {+ "attacker": {+ "infantry_t6": {+ "troops": 500,+ "survivors": 0,+ "losses": 0,+ "injured": 175,+ "lightly_injured": 325,+ "kills": 38+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 150,+ "survivors": 43,+ "losses": 0,+ "injured": 38,+ "lightly_injured": 69,+ "kills": 175+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Wayne": {+ "Fleet": {+ "triggered": 11,+ "displayed_kills": 2+ },+ "Thunder Strike": {+ "triggered": 27,+ "displayed_kills": 4+ },+ "Roundabout Hit": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ },+ "defender": {+ "Sonya": {+ "Bounty Temptation": {+ "triggered": 68,+ "displayed_kills": 12+ },+ "Torrential Impact": {+ "triggered": 27,+ "displayed_kills": 14+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/skill_buckets_20260928/control_edith.json===================================================================--- testcases/emulator_verified/skill_buckets_20260928/control_edith.json prev run+++ testcases/emulator_verified/skill_buckets_20260928/control_edith.json this run@@ -0,0 +1,127 @@+[+ {+ "test_id": "control_edith",+ "description": "C2 battle report 2734693171494518",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "marksman_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Edith": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "marksman_t6": 1600+ },+ "stats": {+ "infantry": {+ "attack": 401.82,+ "defense": 394.37,+ "lethality": 193.33,+ "health": 198.83+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-28T11:57:05.000Z",+ "randomseed": 1790596626,+ "attacker": 0,+ "defender": 253,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171494518",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-28T11-57-22.133Z-d2210b4b-5d72-4e97-85f4-36f980d409b2.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 472+ },+ "defender": {+ "troops": 1600,+ "survivors": 253,+ "losses": 0,+ "injured": 472,+ "lightly_injured": 875,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 472+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1600,+ "survivors": 253,+ "losses": 0,+ "injured": 472,+ "lightly_injured": 875,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/skill_buckets_20260928/control_gatot.json===================================================================--- testcases/emulator_verified/skill_buckets_20260928/control_gatot.json prev run+++ testcases/emulator_verified/skill_buckets_20260928/control_gatot.json this run@@ -0,0 +1,135 @@+[+ {+ "test_id": "control_gatot",+ "description": "C2 battle report 2734693171494510",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "marksman_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ }+ },+ "troops": {+ "marksman_t6": 1600+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-28T11:57:01.000Z",+ "randomseed": 1790596622,+ "attacker": 0,+ "defender": 455,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171494510",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-28T11-57-17.129Z-d4028e1e-1730-4e52-b354-8a6350942045.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 401+ },+ "defender": {+ "troops": 1600,+ "survivors": 455,+ "losses": 0,+ "injured": 401,+ "lightly_injured": 744,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 401+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1600,+ "survivors": 455,+ "losses": 0,+ "injured": 401,+ "lightly_injured": 744,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {+ "Gatot": {+ "King's Bestowal": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/skill_buckets_20260928/control_jessie.json===================================================================--- testcases/emulator_verified/skill_buckets_20260928/control_jessie.json prev run+++ testcases/emulator_verified/skill_buckets_20260928/control_jessie.json this run@@ -0,0 +1,126 @@+[+ {+ "test_id": "control_jessie",+ "description": "C2 battle report 2734693171494632",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "marksman_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Jessie": {+ "skill_1": 1,+ "skill_2": 1+ }+ },+ "troops": {+ "marksman_t6": 1600+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 297.72,+ "defense": 297.02,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-28T11:58:35.000Z",+ "randomseed": 1790596716,+ "attacker": 0,+ "defender": 276,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171494632",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-28T11-58-52.138Z-835f14e4-8e33-4f5f-a91d-6e9d35d75b73.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 464+ },+ "defender": {+ "troops": 1600,+ "survivors": 276,+ "losses": 0,+ "injured": 464,+ "lightly_injured": 860,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 464+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1600,+ "survivors": 276,+ "losses": 0,+ "injured": 464,+ "lightly_injured": 860,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/skill_buckets_20260928/control_ling.json===================================================================--- testcases/emulator_verified/skill_buckets_20260928/control_ling.json prev run+++ testcases/emulator_verified/skill_buckets_20260928/control_ling.json this run@@ -0,0 +1,126 @@+[+ {+ "test_id": "control_ling",+ "description": "C2 battle report 2734693171494630",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "marksman_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Ling Xue": {+ "skill_1": 1,+ "skill_2": 1+ }+ },+ "troops": {+ "marksman_t6": 1600+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 256.45,+ "defense": 255.75,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-28T11:58:34.000Z",+ "randomseed": 1790596715,+ "attacker": 0,+ "defender": 155,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171494630",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-28T11-58-50.135Z-e3817263-c1e0-4a04-8aec-203b1d5c8db6.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 506+ },+ "defender": {+ "troops": 1600,+ "survivors": 155,+ "losses": 0,+ "injured": 506,+ "lightly_injured": 939,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 506+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1600,+ "survivors": 155,+ "losses": 0,+ "injured": 506,+ "lightly_injured": 939,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/skill_buckets_20260928/control_lumak.json===================================================================--- testcases/emulator_verified/skill_buckets_20260928/control_lumak.json prev run+++ testcases/emulator_verified/skill_buckets_20260928/control_lumak.json this run@@ -0,0 +1,126 @@+[+ {+ "test_id": "control_lumak",+ "description": "C2 battle report 2734693171494627",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "marksman_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Lumak Bokan": {+ "skill_1": 3,+ "skill_2": 1+ }+ },+ "troops": {+ "marksman_t6": 1600+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 266.12,+ "defense": 265.42,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-28T11:58:31.000Z",+ "randomseed": 1790596712,+ "attacker": 0,+ "defender": 333,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171494627",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-28T11-58-47.130Z-8a2afa27-72cb-476f-80c6-f9e7b9e912cf.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 444+ },+ "defender": {+ "troops": 1600,+ "survivors": 333,+ "losses": 0,+ "injured": 444,+ "lightly_injured": 823,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 444+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1600,+ "survivors": 333,+ "losses": 0,+ "injured": 444,+ "lightly_injured": 823,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/skill_buckets_20260928/control_none.json===================================================================--- testcases/emulator_verified/skill_buckets_20260928/control_none.json prev run+++ testcases/emulator_verified/skill_buckets_20260928/control_none.json this run@@ -0,0 +1,121 @@+[+ {+ "test_id": "control_none",+ "description": "C2 battle report 2734693171494513",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "marksman_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {},+ "troops": {+ "marksman_t6": 1600+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-28T11:57:03.000Z",+ "randomseed": 1790596624,+ "attacker": 19,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171494513",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-28T11-57-19.129Z-82839fe4-687d-4555-b57a-5bf731d298f9.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1000,+ "survivors": 19,+ "losses": 0,+ "injured": 344,+ "lightly_injured": 637,+ "kills": 560+ },+ "defender": {+ "troops": 1600,+ "survivors": 0,+ "losses": 0,+ "injured": 560,+ "lightly_injured": 1040,+ "kills": 344+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 1000,+ "survivors": 19,+ "losses": 0,+ "injured": 344,+ "lightly_injured": 637,+ "kills": 560+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1600,+ "survivors": 0,+ "losses": 0,+ "injured": 560,+ "lightly_injured": 1040,+ "kills": 344+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/skill_buckets_20260928/edith_jessie.json===================================================================--- testcases/emulator_verified/skill_buckets_20260928/edith_jessie.json prev run+++ testcases/emulator_verified/skill_buckets_20260928/edith_jessie.json this run@@ -0,0 +1,131 @@+[+ {+ "test_id": "edith_jessie",+ "description": "C2 battle report 2734693171494661",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "marksman_t6": 1110+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Edith": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ },+ "Jessie": {+ "skill_1": 1,+ "skill_2": 1+ }+ },+ "troops": {+ "marksman_t6": 1600+ },+ "stats": {+ "infantry": {+ "attack": 401.82,+ "defense": 394.37,+ "lethality": 193.33,+ "health": 198.83+ },+ "lancer": {+ "attack": 297.72,+ "defense": 297.02,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-28T12:01:05.000Z",+ "randomseed": 1790596866,+ "attacker": 0,+ "defender": 17,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171494661",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-28T12-01-21.135Z-932aac26-79c8-4ab5-86ad-038e6ca39e00.json",+ "winner": "defender",+ "attacker": {+ "troops": 1110,+ "survivors": 0,+ "losses": 0,+ "injured": 389,+ "lightly_injured": 721,+ "kills": 555+ },+ "defender": {+ "troops": 1600,+ "survivors": 17,+ "losses": 0,+ "injured": 555,+ "lightly_injured": 1028,+ "kills": 389+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 1110,+ "survivors": 0,+ "losses": 0,+ "injured": 389,+ "lightly_injured": 721,+ "kills": 555+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1600,+ "survivors": 17,+ "losses": 0,+ "injured": 555,+ "lightly_injured": 1028,+ "kills": 389+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/skill_buckets_20260928/edith_ling.json===================================================================--- testcases/emulator_verified/skill_buckets_20260928/edith_ling.json prev run+++ testcases/emulator_verified/skill_buckets_20260928/edith_ling.json this run@@ -0,0 +1,131 @@+[+ {+ "test_id": "edith_ling",+ "description": "C2 battle report 2734693171494667",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "marksman_t6": 1070+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Edith": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ },+ "Ling Xue": {+ "skill_1": 1,+ "skill_2": 1+ }+ },+ "troops": {+ "marksman_t6": 1600+ },+ "stats": {+ "infantry": {+ "attack": 401.82,+ "defense": 394.37,+ "lethality": 193.33,+ "health": 198.83+ },+ "lancer": {+ "attack": 256.45,+ "defense": 255.75,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-28T12:02:03.000Z",+ "randomseed": 1790596924,+ "attacker": 0,+ "defender": 66,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171494667",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-28T12-02-19.132Z-c704efe9-5f35-4cc7-a1a9-9852a25c61af.json",+ "winner": "defender",+ "attacker": {+ "troops": 1070,+ "survivors": 0,+ "losses": 0,+ "injured": 375,+ "lightly_injured": 695,+ "kills": 537+ },+ "defender": {+ "troops": 1600,+ "survivors": 66,+ "losses": 0,+ "injured": 537,+ "lightly_injured": 997,+ "kills": 375+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 1070,+ "survivors": 0,+ "losses": 0,+ "injured": 375,+ "lightly_injured": 695,+ "kills": 537+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1600,+ "survivors": 66,+ "losses": 0,+ "injured": 537,+ "lightly_injured": 997,+ "kills": 375+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/skill_buckets_20260928/edith_lumak.json===================================================================--- testcases/emulator_verified/skill_buckets_20260928/edith_lumak.json prev run+++ testcases/emulator_verified/skill_buckets_20260928/edith_lumak.json this run@@ -0,0 +1,131 @@+[+ {+ "test_id": "edith_lumak",+ "description": "C2 battle report 2734693171494648",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "marksman_t6": 1130+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Edith": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ },+ "Lumak Bokan": {+ "skill_1": 3,+ "skill_2": 1+ }+ },+ "troops": {+ "marksman_t6": 1600+ },+ "stats": {+ "infantry": {+ "attack": 401.82,+ "defense": 394.37,+ "lethality": 193.33,+ "health": 198.83+ },+ "lancer": {+ "attack": 266.12,+ "defense": 265.42,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-28T11:59:39.000Z",+ "randomseed": 1790596780,+ "attacker": 0,+ "defender": 25,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171494648",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-28T11-59-55.143Z-9d0d266c-1d92-4ffc-88c9-e2bafbe06fee.json",+ "winner": "defender",+ "attacker": {+ "troops": 1130,+ "survivors": 0,+ "losses": 0,+ "injured": 396,+ "lightly_injured": 734,+ "kills": 552+ },+ "defender": {+ "troops": 1600,+ "survivors": 25,+ "losses": 0,+ "injured": 552,+ "lightly_injured": 1023,+ "kills": 396+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 1130,+ "survivors": 0,+ "losses": 0,+ "injured": 396,+ "lightly_injured": 734,+ "kills": 552+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1600,+ "survivors": 25,+ "losses": 0,+ "injured": 552,+ "lightly_injured": 1023,+ "kills": 396+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/skill_buckets_20260928/gatot_jessie.json===================================================================--- testcases/emulator_verified/skill_buckets_20260928/gatot_jessie.json prev run+++ testcases/emulator_verified/skill_buckets_20260928/gatot_jessie.json this run@@ -0,0 +1,139 @@+[+ {+ "test_id": "gatot_jessie",+ "description": "C2 battle report 2734693171494670",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "marksman_t6": 1190+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Jessie": {+ "skill_1": 1,+ "skill_2": 1+ }+ },+ "troops": {+ "marksman_t6": 1600+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 297.72,+ "defense": 297.02,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-28T12:02:06.000Z",+ "randomseed": 1790596927,+ "attacker": 0,+ "defender": 42,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171494670",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-28T12-02-22.121Z-96715f93-1687-4860-948e-a5f49a260e2c.json",+ "winner": "defender",+ "attacker": {+ "troops": 1190,+ "survivors": 0,+ "losses": 0,+ "injured": 417,+ "lightly_injured": 773,+ "kills": 546+ },+ "defender": {+ "troops": 1600,+ "survivors": 42,+ "losses": 0,+ "injured": 546,+ "lightly_injured": 1012,+ "kills": 417+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 1190,+ "survivors": 0,+ "losses": 0,+ "injured": 417,+ "lightly_injured": 773,+ "kills": 546+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1600,+ "survivors": 42,+ "losses": 0,+ "injured": 546,+ "lightly_injured": 1012,+ "kills": 417+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {+ "Gatot": {+ "King's Bestowal": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/skill_buckets_20260928/gatot_ling.json===================================================================--- testcases/emulator_verified/skill_buckets_20260928/gatot_ling.json prev run+++ testcases/emulator_verified/skill_buckets_20260928/gatot_ling.json this run@@ -0,0 +1,139 @@+[+ {+ "test_id": "gatot_ling",+ "description": "C2 battle report 2734693171494651",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "marksman_t6": 1150+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Ling Xue": {+ "skill_1": 1,+ "skill_2": 1+ }+ },+ "troops": {+ "marksman_t6": 1600+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 256.45,+ "defense": 255.75,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-28T11:59:42.000Z",+ "randomseed": 1790596783,+ "attacker": 0,+ "defender": 16,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171494651",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-28T11-59-58.126Z-b3ed1a33-d75c-4323-a002-563e671499a1.json",+ "winner": "defender",+ "attacker": {+ "troops": 1150,+ "survivors": 0,+ "losses": 0,+ "injured": 403,+ "lightly_injured": 747,+ "kills": 555+ },+ "defender": {+ "troops": 1600,+ "survivors": 16,+ "losses": 0,+ "injured": 555,+ "lightly_injured": 1029,+ "kills": 403+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 1150,+ "survivors": 0,+ "losses": 0,+ "injured": 403,+ "lightly_injured": 747,+ "kills": 555+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1600,+ "survivors": 16,+ "losses": 0,+ "injured": 555,+ "lightly_injured": 1029,+ "kills": 403+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {+ "Gatot": {+ "King's Bestowal": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/skill_buckets_20260928/gatot_lumak.json===================================================================--- testcases/emulator_verified/skill_buckets_20260928/gatot_lumak.json prev run+++ testcases/emulator_verified/skill_buckets_20260928/gatot_lumak.json this run@@ -0,0 +1,139 @@+[+ {+ "test_id": "gatot_lumak",+ "description": "C2 battle report 2734693171494663",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "marksman_t6": 1210+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gatot": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4,+ "skill_4": 0+ },+ "Lumak Bokan": {+ "skill_1": 3,+ "skill_2": 1+ }+ },+ "troops": {+ "marksman_t6": 1600+ },+ "stats": {+ "infantry": {+ "attack": 627.31,+ "defense": 619.86,+ "lethality": 230.66,+ "health": 281.02+ },+ "lancer": {+ "attack": 266.12,+ "defense": 265.42,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-28T12:01:08.000Z",+ "randomseed": 1790596869,+ "attacker": 0,+ "defender": 44,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171494663",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-28T12-01-24.139Z-8d199e5a-6c8d-4a33-9700-38923a5fb591.json",+ "winner": "defender",+ "attacker": {+ "troops": 1210,+ "survivors": 0,+ "losses": 0,+ "injured": 424,+ "lightly_injured": 786,+ "kills": 545+ },+ "defender": {+ "troops": 1600,+ "survivors": 44,+ "losses": 0,+ "injured": 545,+ "lightly_injured": 1011,+ "kills": 424+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 1210,+ "survivors": 0,+ "losses": 0,+ "injured": 424,+ "lightly_injured": 786,+ "kills": 545+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1600,+ "survivors": 44,+ "losses": 0,+ "injured": 545,+ "lightly_injured": 1011,+ "kills": 424+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {+ "Gatot": {+ "King's Bestowal": {+ "triggered": null,+ "displayed_kills": null+ }+ }+ }+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/skill_buckets_20260928/sergey_ling_level3_matched.json===================================================================--- testcases/emulator_verified/skill_buckets_20260928/sergey_ling_level3_matched.json prev run+++ testcases/emulator_verified/skill_buckets_20260928/sergey_ling_level3_matched.json this run@@ -0,0 +1,130 @@+[+ {+ "test_id": "sergey_ling_level3_matched",+ "description": "C2 battle report 2734693171496487",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "marksman_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Sergey": {+ "skill_1": 2,+ "skill_2": 2+ },+ "Ling Xue": {+ "skill_1": 3,+ "skill_2": 1+ }+ },+ "troops": {+ "marksman_t6": 1600+ },+ "stats": {+ "infantry": {+ "attack": 346.14,+ "defense": 338.69,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 256.45,+ "defense": 255.75,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-28T13:03:31.000Z",+ "randomseed": 1790600612,+ "attacker": 0,+ "defender": 569,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171496487",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-28T13-03-47.127Z-35ac5e5b-6386-48ee-a48f-9e464512d33b.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 361+ },+ "defender": {+ "troops": 1600,+ "survivors": 569,+ "losses": 0,+ "injured": 361,+ "lightly_injured": 670,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 361+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1600,+ "survivors": 569,+ "losses": 0,+ "injured": 361,+ "lightly_injured": 670,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/skill_buckets_20260928/sergey_ling_matched.json===================================================================--- testcases/emulator_verified/skill_buckets_20260928/sergey_ling_matched.json prev run+++ testcases/emulator_verified/skill_buckets_20260928/sergey_ling_matched.json this run@@ -0,0 +1,130 @@+[+ {+ "test_id": "sergey_ling_matched",+ "description": "C2 battle report 2734693171496167",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "marksman_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Sergey": {+ "skill_1": 2,+ "skill_2": 2+ },+ "Ling Xue": {+ "skill_1": 1,+ "skill_2": 1+ }+ },+ "troops": {+ "marksman_t6": 1600+ },+ "stats": {+ "infantry": {+ "attack": 346.14,+ "defense": 338.69,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 256.45,+ "defense": 255.75,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-28T12:52:00.000Z",+ "randomseed": 1790599921,+ "attacker": 0,+ "defender": 468,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171496167",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-28T12-52-16.135Z-c9353ef0-220e-4fa5-943e-cfe104615f98.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 397+ },+ "defender": {+ "troops": 1600,+ "survivors": 468,+ "losses": 0,+ "injured": 397,+ "lightly_injured": 735,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 397+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1600,+ "survivors": 468,+ "losses": 0,+ "injured": 397,+ "lightly_injured": 735,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/skill_buckets_20260928/sergey_lumak_matched.json===================================================================--- testcases/emulator_verified/skill_buckets_20260928/sergey_lumak_matched.json prev run+++ testcases/emulator_verified/skill_buckets_20260928/sergey_lumak_matched.json this run@@ -0,0 +1,130 @@+[+ {+ "test_id": "sergey_lumak_matched",+ "description": "C2 battle report 2734693171496195",+ "attacker": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "marksman_t6": 1000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 292.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 286.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 289.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Sergey": {+ "skill_1": 2,+ "skill_2": 2+ },+ "Lumak Bokan": {+ "skill_1": 3,+ "skill_2": 1+ }+ },+ "troops": {+ "marksman_t6": 1600+ },+ "stats": {+ "infantry": {+ "attack": 346.14,+ "defense": 338.69,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 266.12,+ "defense": 265.42,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-28T12:53:06.000Z",+ "randomseed": 1790599987,+ "attacker": 0,+ "defender": 580,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171496195",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-28T12-53-22.137Z-19e6e485-8f82-4d93-af60-20bed14661ee.json",+ "winner": "defender",+ "attacker": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 357+ },+ "defender": {+ "troops": 1600,+ "survivors": 580,+ "losses": 0,+ "injured": 357,+ "lightly_injured": 663,+ "kills": 350+ },+ "troop_details": {+ "attacker": {+ "marksman_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 357+ }+ },+ "defender": {+ "marksman_t6": {+ "troops": 1600,+ "survivors": 580,+ "losses": 0,+ "injured": 357,+ "lightly_injured": 663,+ "kills": 350+ }+ }+ },+ "skill_details": {+ "attacker": {},+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/wip_renee_gwen_no_blastmaster_20260925/wip_gwen_only_1000l_300m_vs_3000l.json===================================================================--- testcases/emulator_verified/wip_renee_gwen_no_blastmaster_20260925/wip_gwen_only_1000l_300m_vs_3000l.json prev run+++ testcases/emulator_verified/wip_renee_gwen_no_blastmaster_20260925/wip_gwen_only_1000l_300m_vs_3000l.json this run@@ -0,0 +1,143 @@+[+ {+ "test_id": "wip_gwen_only_1000l_300m_vs_3000l",+ "description": "C2 battle report 2734693171348034",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 208.71,+ "defense": 208.01,+ "lethality": 187,+ "health": 186.06+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 3000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T11:32:06.000Z",+ "randomseed": 1790335927,+ "attacker": 0,+ "defender": 2320,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171348034",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T11-32-31.084Z-3864b2e5-edf5-4ad2-8936-2cb556d0c85f.json",+ "winner": "defender",+ "attacker": {+ "troops": 1300,+ "survivors": 0,+ "losses": 0,+ "injured": 455,+ "lightly_injured": 845,+ "kills": 238+ },+ "defender": {+ "troops": 3000,+ "survivors": 2320,+ "losses": 0,+ "injured": 238,+ "lightly_injured": 442,+ "kills": 455+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 83+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 155+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 3000,+ "survivors": 2320,+ "losses": 0,+ "injured": 238,+ "lightly_injured": 442,+ "kills": 455+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 4,+ "displayed_kills": 5+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/wip_renee_gwen_no_blastmaster_20260925/wip_renee_gwen_1000l_300m_vs_3000l.json===================================================================--- testcases/emulator_verified/wip_renee_gwen_no_blastmaster_20260925/wip_renee_gwen_1000l_300m_vs_3000l.json prev run+++ testcases/emulator_verified/wip_renee_gwen_no_blastmaster_20260925/wip_renee_gwen_1000l_300m_vs_3000l.json this run@@ -0,0 +1,155 @@+[+ {+ "test_id": "wip_renee_gwen_1000l_300m_vs_3000l",+ "description": "C2 battle report 2734693171347991",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 3000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T11:29:09.000Z",+ "randomseed": 1790335750,+ "attacker": 747,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171347991",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T11-29-34.084Z-70edc78c-b413-4871-af89-8dec7060a27a.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1300,+ "survivors": 747,+ "losses": 0,+ "injured": 194,+ "lightly_injured": 359,+ "kills": 1050+ },+ "defender": {+ "troops": 3000,+ "survivors": 0,+ "losses": 0,+ "injured": 1050,+ "lightly_injured": 1950,+ "kills": 194+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 447,+ "losses": 0,+ "injured": 194,+ "lightly_injured": 359,+ "kills": 741+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 300,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 309+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 3000,+ "survivors": 0,+ "losses": 0,+ "injured": 1050,+ "lightly_injured": 1950,+ "kills": 194+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 6,+ "displayed_kills": 16+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 11,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/wip_renee_gwen_no_blastmaster_20260925/wip_renee_gwen_1000l_300m_vs_4500l.json===================================================================--- testcases/emulator_verified/wip_renee_gwen_no_blastmaster_20260925/wip_renee_gwen_1000l_300m_vs_4500l.json prev run+++ testcases/emulator_verified/wip_renee_gwen_no_blastmaster_20260925/wip_renee_gwen_1000l_300m_vs_4500l.json this run@@ -0,0 +1,155 @@+[+ {+ "test_id": "wip_renee_gwen_1000l_300m_vs_4500l",+ "description": "C2 battle report 2734693171348058",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ },+ "Gwen": {+ "skill_1": 2,+ "skill_2": 1,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 344.4,+ "defense": 333.2,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 4500+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T11:33:30.000Z",+ "randomseed": 1790336011,+ "attacker": 0,+ "defender": 1046,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171348058",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T11-33-55.086Z-ce82bc14-acd7-4786-819b-8905a462eb1e.json",+ "winner": "defender",+ "attacker": {+ "troops": 1300,+ "survivors": 0,+ "losses": 0,+ "injured": 455,+ "lightly_injured": 845,+ "kills": 1209+ },+ "defender": {+ "troops": 4500,+ "survivors": 1046,+ "losses": 0,+ "injured": 1209,+ "lightly_injured": 2245,+ "kills": 455+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 0,+ "losses": 0,+ "injured": 350,+ "lightly_injured": 650,+ "kills": 741+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 0,+ "losses": 0,+ "injured": 105,+ "lightly_injured": 195,+ "kills": 468+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 4500,+ "survivors": 1046,+ "losses": 0,+ "injured": 1209,+ "lightly_injured": 2245,+ "kills": 455+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Gwen": {+ "Air Dominance": {+ "triggered": 9,+ "displayed_kills": 21+ }+ },+ "Renee": {+ "Nightmare Trace": {+ "triggered": 17,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/emulator_verified/wip_renee_gwen_no_blastmaster_20260925/wip_renee_only_1000l_300m_vs_3000l.json===================================================================--- testcases/emulator_verified/wip_renee_gwen_no_blastmaster_20260925/wip_renee_only_1000l_300m_vs_3000l.json prev run+++ testcases/emulator_verified/wip_renee_gwen_no_blastmaster_20260925/wip_renee_only_1000l_300m_vs_3000l.json this run@@ -0,0 +1,144 @@+[+ {+ "test_id": "wip_renee_only_1000l_300m_vs_3000l",+ "description": "C2 battle report 2734693171348029",+ "attacker": {+ "name": "[BBQ]XxWIPxX",+ "heroes": {+ "Renee": {+ "skill_1": 3,+ "skill_2": 3,+ "skill_3": 3,+ "skill_4": 0+ }+ },+ "troops": {+ "lancer_t6": 1000,+ "marksman_t6": 300+ },+ "stats": {+ "infantry": {+ "attack": 257.13,+ "defense": 249.68,+ "lethality": 188,+ "health": 193.5+ },+ "lancer": {+ "attack": 482.4,+ "defense": 481.7,+ "lethality": 252.8,+ "health": 239.41+ },+ "marksman": {+ "attack": 230.96,+ "defense": 219.76,+ "lethality": 181.53,+ "health": 177.16+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "[ARK]Piddlyminxxx",+ "heroes": {},+ "troops": {+ "lancer_t6": 3000+ },+ "stats": {+ "infantry": {+ "attack": 304.95,+ "defense": 287.95,+ "lethality": 244.04,+ "health": 238.39+ },+ "lancer": {+ "attack": 286.92,+ "defense": 281.17,+ "lethality": 224.32,+ "health": 229.95+ },+ "marksman": {+ "attack": 288.42,+ "defense": 284.42,+ "lethality": 235.76,+ "health": 230.26+ }+ },+ "joiner_heroes": {}+ },+ "engagement_type": "solo",+ "game_report_result": [+ {+ "timestamp": "2026-09-25T11:30:39.000Z",+ "randomseed": 1790335840,+ "attacker": 665,+ "defender": 0,+ "metadata": {+ "source": "c2",+ "report_reference": "2734693171348029",+ "battle_type": "atk_camp",+ "stat_units": "percentage_points",+ "raw_trace_file": "../../../c2/data/runs/2026-09-25T11-31-04.084Z-e89f84db-5bf3-465e-8b57-df669a878ac2.json",+ "winner": "attacker",+ "attacker": {+ "troops": 1300,+ "survivors": 665,+ "losses": 0,+ "injured": 223,+ "lightly_injured": 412,+ "kills": 1050+ },+ "defender": {+ "troops": 3000,+ "survivors": 0,+ "losses": 0,+ "injured": 1050,+ "lightly_injured": 1950,+ "kills": 223+ },+ "troop_details": {+ "attacker": {+ "lancer_t6": {+ "troops": 1000,+ "survivors": 365,+ "losses": 0,+ "injured": 223,+ "lightly_injured": 412,+ "kills": 802+ },+ "marksman_t6": {+ "troops": 300,+ "survivors": 300,+ "losses": 0,+ "injured": 0,+ "lightly_injured": 0,+ "kills": 248+ }+ },+ "defender": {+ "lancer_t6": {+ "troops": 3000,+ "survivors": 0,+ "losses": 0,+ "injured": 1050,+ "lightly_injured": 1950,+ "kills": 223+ }+ }+ },+ "skill_details": {+ "attacker": {+ "Renee": {+ "Nightmare Trace": {+ "triggered": 13,+ "displayed_kills": null+ }+ }+ },+ "defender": {}+ }+ }+ }+ ]+ }+]Index: testcases/heroes_unittests/Flint_tc.json===================================================================--- testcases/heroes_unittests/Flint_tc.json prev run+++ testcases/heroes_unittests/Flint_tc.json this run@@ -1,216 +0,0 @@-[- {- "test_id": "flint_tc_1",- "time": "2025-07-20 - 03:49",- "attacker": {- "name": "daut",- "heroes": {},- "troops": {- "infantry_t6": 1000,- "lancer_t6": 500,- "marksman_t6": 500- },- "stats": {- "inf": {- "attack": 9.94,- "defense": 9.44,- "lethality": 1.75,- "health": 1.75- },- "lanc": {- "attack": 9.94,- "defense": 9.44,- "lethality": 1.75,- "health": 1.75- },- "mark": {- "attack": 10.43,- "defense": 9.44,- "lethality": 1.75,- "health": 1.75- }- },- "joiner_heroes": {}- },- "defender": {- "name": "viper",- "heroes": {- "Flint": {- "skill_1": 4,- "skill_2": 4,- "skill_3": 4- }- },- "troops": {- "infantry_t6": 100,- "lancer_t6": 50,- "marksman_t6": 50- },- "stats": {- "inf": {- "attack": 313.87,- "defense": 317.37,- "lethality": 107.24,- "health": 114.18- },- "lanc": {- "attack": 167.0,- "defense": 163.0,- "lethality": 110.31,- "health": 100.21- },- "mark": {- "attack": 174.75,- "defense": 168.25,- "lethality": 117.75,- "health": 104.74- }- },- "joiner_heroes": {}- },- "sim_skills_used": {- "attacker": {- "MARKSMEN- Ranged Strike/1": "1 (22)"- },- "defender": {- "Flint- Pyromaniac/1": "10 (24)",- "Flint- Burning resolve/1": "1 (66)",- "Flint- Immolation/1": "34 (102)",- "INFANTRY- Master Brawler/1": "1 (2)",- "LANCERS- Charge/1": "1 (2)",- "MARKSMEN- Ranged Strike/1": "1 (18)"- }- },- "game_report_result": [- {- "attacker": 0,- "defender": 150- },- {- "attacker": 0,- "defender": 151- },- {- "attacker": 0,- "defender": 149- },- {- "attacker": 0,- "defender": 149- },- {- "attacker": 0,- "defender": 150- }- ]- },- {- "test_id": "flint_tc_2",- "time": "2025-07-20 - 04:07",- "attacker": {- "name": "daut",- "heroes": {},- "troops": {- "infantry_t6": 3000,- "lancer_t6": 2000,- "marksman_t6": 2000- },- "stats": {- "inf": {- "attack": 9.94,- "defense": 9.44,- "lethality": 1.75,- "health": 1.75- },- "lanc": {- "attack": 9.94,- "defense": 9.44,- "lethality": 1.75,- "health": 1.75- },- "mark": {- "attack": 10.43,- "defense": 9.44,- "lethality": 1.75,- "health": 1.75- }- },- "joiner_heroes": {}- },- "defender": {- "name": "viper",- "heroes": {- "Flint": {- "skill_1": 4,- "skill_2": 4,- "skill_3": 4- }- },- "troops": {- "infantry_t6": 100,- "lancer_t6": 50,- "marksman_t6": 50- },- "stats": {- "inf": {- "attack": 313.87,- "defense": 317.37,- "lethality": 107.24,- "health": 114.18- },- "lanc": {- "attack": 167.0,- "defense": 163.0,- "lethality": 110.31,- "health": 100.21- },- "mark": {- "attack": 174.75,- "defense": 168.25,- "lethality": 117.75,- "health": 104.74- }- },- "joiner_heroes": {}- },- "sim_skills_used": {- "attacker": {- "INFANTRY- Master Brawler/1": "1 (1)",- "LANCERS- Charge/1": "1 (5)",- "MARKSMEN- Ranged Strike/1": "1 (46)"- },- "defender": {- "Flint- Pyromaniac/1": "34 (100)",- "Flint- Burning resolve/1": "1 (155)",- "Flint- Immolation/1": "85 (245)",- "MARKSMEN- Ranged Strike/1": "1 (47)"- }- },- "game_report_result": [- {- "attacker": 5720,- "defender": 0- },- {- "attacker": 5756,- "defender": 0- },- {- "attacker": 5736,- "defender": 0- },- {- "attacker": 5715,- "defender": 0- },- {- "attacker": 5733,- "defender": 0- },- {- "attacker": 5736,- "defender": 0- }- ]- }-]\ No newline at end of fileIndex: testcases/heroes_unittests/Flint_tc.json.disabled===================================================================--- testcases/heroes_unittests/Flint_tc.json.disabled prev run+++ testcases/heroes_unittests/Flint_tc.json.disabled this run@@ -0,0 +1,218 @@+[+ {+ "test_id": "flint_tc_1",+ "time": "2025-07-20 - 03:49",+ "disabled_reason": "Historical 2025-07-20 reports use Flint's stochastic skill kit, not the current permanent bonuses. At that time Pyromaniac had a 20% burn proc and Immolation a 50% damage-taken proc (git 6b223c2f^:assets/hero_skills/Flint.json). Current extracted client skills 500214/500215/500216 instead grant infantry damage, all-troop attack and all-troop lethality (c2/data/client-schema-wip/config/skills.json). Preserve these outcomes as historical evidence; do not calibrate the current simulator against them.",+ "attacker": {+ "name": "daut",+ "heroes": {},+ "troops": {+ "infantry_t6": 1000,+ "lancer_t6": 500,+ "marksman_t6": 500+ },+ "stats": {+ "inf": {+ "attack": 9.94,+ "defense": 9.44,+ "lethality": 1.75,+ "health": 1.75+ },+ "lanc": {+ "attack": 9.94,+ "defense": 9.44,+ "lethality": 1.75,+ "health": 1.75+ },+ "mark": {+ "attack": 10.43,+ "defense": 9.44,+ "lethality": 1.75,+ "health": 1.75+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "viper",+ "heroes": {+ "Flint": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4+ }+ },+ "troops": {+ "infantry_t6": 100,+ "lancer_t6": 50,+ "marksman_t6": 50+ },+ "stats": {+ "inf": {+ "attack": 313.87,+ "defense": 317.37,+ "lethality": 107.24,+ "health": 114.18+ },+ "lanc": {+ "attack": 167.0,+ "defense": 163.0,+ "lethality": 110.31,+ "health": 100.21+ },+ "mark": {+ "attack": 174.75,+ "defense": 168.25,+ "lethality": 117.75,+ "health": 104.74+ }+ },+ "joiner_heroes": {}+ },+ "sim_skills_used": {+ "attacker": {+ "MARKSMEN- Ranged Strike/1": "1 (22)"+ },+ "defender": {+ "Flint- Pyromaniac/1": "10 (24)",+ "Flint- Burning resolve/1": "1 (66)",+ "Flint- Immolation/1": "34 (102)",+ "INFANTRY- Master Brawler/1": "1 (2)",+ "LANCERS- Charge/1": "1 (2)",+ "MARKSMEN- Ranged Strike/1": "1 (18)"+ }+ },+ "game_report_result": [+ {+ "attacker": 0,+ "defender": 150+ },+ {+ "attacker": 0,+ "defender": 151+ },+ {+ "attacker": 0,+ "defender": 149+ },+ {+ "attacker": 0,+ "defender": 149+ },+ {+ "attacker": 0,+ "defender": 150+ }+ ]+ },+ {+ "test_id": "flint_tc_2",+ "time": "2025-07-20 - 04:07",+ "disabled_reason": "Historical 2025-07-20 reports use Flint's stochastic skill kit, not the current permanent bonuses. At that time Pyromaniac had a 20% burn proc and Immolation a 50% damage-taken proc (git 6b223c2f^:assets/hero_skills/Flint.json). Current extracted client skills 500214/500215/500216 instead grant infantry damage, all-troop attack and all-troop lethality (c2/data/client-schema-wip/config/skills.json). Preserve these outcomes as historical evidence; do not calibrate the current simulator against them.",+ "attacker": {+ "name": "daut",+ "heroes": {},+ "troops": {+ "infantry_t6": 3000,+ "lancer_t6": 2000,+ "marksman_t6": 2000+ },+ "stats": {+ "inf": {+ "attack": 9.94,+ "defense": 9.44,+ "lethality": 1.75,+ "health": 1.75+ },+ "lanc": {+ "attack": 9.94,+ "defense": 9.44,+ "lethality": 1.75,+ "health": 1.75+ },+ "mark": {+ "attack": 10.43,+ "defense": 9.44,+ "lethality": 1.75,+ "health": 1.75+ }+ },+ "joiner_heroes": {}+ },+ "defender": {+ "name": "viper",+ "heroes": {+ "Flint": {+ "skill_1": 4,+ "skill_2": 4,+ "skill_3": 4+ }+ },+ "troops": {+ "infantry_t6": 100,+ "lancer_t6": 50,+ "marksman_t6": 50+ },+ "stats": {+ "inf": {+ "attack": 313.87,+ "defense": 317.37,+ "lethality": 107.24,+ "health": 114.18+ },+ "lanc": {+ "attack": 167.0,+ "defense": 163.0,+ "lethality": 110.31,+ "health": 100.21+ },+ "mark": {+ "attack": 174.75,+ "defense": 168.25,+ "lethality": 117.75,+ "health": 104.74+ }+ },+ "joiner_heroes": {}+ },+ "sim_skills_used": {+ "attacker": {+ "INFANTRY- Master Brawler/1": "1 (1)",+ "LANCERS- Charge/1": "1 (5)",+ "MARKSMEN- Ranged Strike/1": "1 (46)"+ },+ "defender": {+ "Flint- Pyromaniac/1": "34 (100)",+ "Flint- Burning resolve/1": "1 (155)",+ "Flint- Immolation/1": "85 (245)",+ "MARKSMEN- Ranged Strike/1": "1 (47)"+ }+ },+ "game_report_result": [+ {+ "attacker": 5720,+ "defender": 0+ },+ {+ "attacker": 5756,+ "defender": 0+ },+ {+ "attacker": 5736,+ "defender": 0+ },+ {+ "attacker": 5715,+ "defender": 0+ },+ {+ "attacker": 5733,+ "defender": 0+ },+ {+ "attacker": 5736,+ "defender": 0+ }+ ]+ }+]\ No newline at end of file
Show raw per-run patches
Run A dirty state patch
diff --git a/simulator/config/hero_definitions/Ahmose.json b/simulator/config/hero_definitions/Ahmose.json--- a/simulator/config/hero_definitions/Ahmose.json+++ b/simulator/config/hero_definitions/Ahmose.json@@ -102,7 +102,7 @@},"effects": {"BladeOfLight/1": {- "type": "active.hero.damage.up",+ "type": "extra_skill_attack","value": [12,24,@@ -115,11 +115,12 @@"infantry"]},- "duration": {- "attacks": {- "count": 1+ "trigger_damage_jobs": [+ {+ "source": "use.source",+ "target": "use.target"}- }+ ]},"BladeOfLight/2": {"type": "active.hero.damageTaken.up",diff --git a/simulator/config/hero_definitions/Gordon.json b/simulator/config/hero_definitions/Gordon.json--- a/simulator/config/hero_definitions/Gordon.json+++ b/simulator/config/hero_definitions/Gordon.json@@ -22,8 +22,8 @@100],"units": {- "applies_to": "trigger.source",- "applies_vs": "trigger.target"+ "applies_to": "trigger.source",+ "applies_vs": "trigger.target"},"duration": {"attacks": {@@ -61,6 +61,7 @@"effects": {"ChemicalTerror/1": {"type": "active.hero.damage.up",+ "applies_to_damage_kinds": ["normal"],"value": [30,60,@@ -75,7 +76,8 @@},"duration": {"turns": {- "count": 1+ "count": 1,+ "delay": 1}},"same_effect_stacking": "max"@@ -99,6 +101,28 @@}},"same_effect_stacking": "max"+ },+ "ChemicalTerror/3": {+ "type": "active.hero.damage.up",+ "applies_to_damage_kinds": ["skill"],+ "value": [+ 30,+ 60,+ 90,+ 120,+ 150+ ],+ "units": {+ "applies_to": [+ "lancer"+ ]+ },+ "duration": {+ "turns": {+ "count": 1+ }+ },+ "same_effect_stacking": "max"}}},diff --git a/simulator/config/hero_definitions/README.md b/simulator/config/hero_definitions/README.md--- a/simulator/config/hero_definitions/README.md+++ b/simulator/config/hero_definitions/README.md@@ -459,11 +459,13 @@The extra-attack effect is charged once for the parent normal attack if at least one of its jobs runs. If its `value` is non-positive, every job lacks living source/target troops, or every job is skipped because its target is already exhausted, the effect is not charged and can remain available.-Immediate and delayed hits share the same generation and delivery routines. Generation uses reusable scratch and the prepared modifier-group index to calculate non-shield damage. Delivery selects applicable shields from a small live list, consumes protection, and applies the current target-troop cap. Shield activation and expiry use the ordinary effect scheduler; shields retain group identity for stacking and dependencies but are excluded from the modifier job-shape lists.+Immediate and delayed hits share bucket evaluation, shield settlement, and target caps. Immediate hits calculate and consume their modifiers together. Delayed hits instead separate captured contributions from attack-limited target modifiers.-When an `extra_skill_attack` is materialized as a carrier's `trigger_effects` child, its generated damage is retained on that child ActiveEffect. Fast and standard modes retain scalar calculation state and the recording context; only trace mode copies the full bucket factors. Shields are not selected, advanced, or consumed during generation. The child can deliver its damage only when a later normal attack matches its resolved source and target scope, after that normal hit has resolved. Delivery uses the generation-time health conversion factor for shield-budget conversion without recalculating the damage. If the matching attack never occurs during the child's duration, the pending damage expires without consuming shields.+When an `extra_skill_attack` is materialized as a carrier's `trigger_effects` child, its generated damage is retained on that child ActiveEffect. All modes retain owned dynamic factors and captured static terms so delivery can combine modifiers without recalculating the source's troop strength. Attack-limited target modifiers and shields are not selected, advanced, or consumed during capture. When a later normal attack matches the child's source and target scope, pending damage lands before that attack is declared and before it creates new effects. Delivery applies the currently eligible attack-limited target modifiers to the captured buckets, consumes their uses, and settles live shields and the current target-troop cap. If no matching attack occurs during the child's duration, the pending damage expires without consuming those modifiers or shields.-Renee's Nightmare Trace uses this form with a one-turn delay: the even-round Lancer attack locks the target and calculates the damage, then the following odd-round Lancer attack delivers it. The precise capture ordering and treatment of defensive state are provisional reverse-engineering assumptions, not confirmed game mechanics.+Renee's Nightmare Trace uses this form with a one-turn delay: the even-round Lancer attack locks the target and calculates the damage, then a matching allied attack on the following odd round delivers it. Its child uses `self.any` for delivery eligibility; the retained job still uses the original Lancer source and locked target, allowing delivery after the Lancers die. The precise capture ordering and treatment of defensive state remain provisional reverse-engineering assumptions.++Renee's Dreamslice mark increases both normal and skill damage taken by the marked target. Dreamcatcher's Lancer-specific increase remains restricted to normal damage.All jobs emitted by one use read the parent extra-attack effect's same current `value`; its use/evolution is charged only after those jobs finish. Other attack-limited **modifier** effects are different: each generated skill job is a separate modifier use, and modifiers are charged after each job, so a one-job modifier can expire before the second target in the same extra attack is calculated.diff --git a/simulator/config/hero_definitions/Renee.json b/simulator/config/hero_definitions/Renee.json--- a/simulator/config/hero_definitions/Renee.json+++ b/simulator/config/hero_definitions/Renee.json@@ -24,7 +24,7 @@"type": "extra_skill_attack","value": [40, 80, 120, 160, 200],"units": {- "applies_to": "parent.use.source",+ "applies_to": "self.any","applies_vs": "parent.use.target"},"trigger_damage_jobs": [@@ -96,7 +96,6 @@"trigger_effects": {"Dreamslice/1": {"type": "active.hero.damageTaken.up",- "applies_to_damage_kinds": ["normal"],"value": [15, 30, 45, 60, 75],"units": {"applies_to": "parent.use.target",diff --git a/simulator/src/damage.test.ts b/simulator/src/damage.test.ts--- a/simulator/src/damage.test.ts+++ b/simulator/src/damage.test.ts@@ -107,6 +107,9 @@group = {ordinal: groups.length,bucketIndex: DYNAMIC_BUCKETS.findIndex((definition) => definition.name === activeEffect.intent.type),+ attackLimitedTakerModifier: activeEffect.kind === "modifier" &&+ activeEffect.duration.attacks !== undefined &&+ DYNAMIC_BUCKETS.find(definition => definition.name === activeEffect.intent.type)?.jobSide === "taker",sameEffectStacking: activeEffect.sameEffectStacking};byResolvedGroup.set(key, group);diff --git a/simulator/src/damage.ts b/simulator/src/damage.ts--- a/simulator/src/damage.ts+++ b/simulator/src/damage.ts@@ -115,13 +115,15 @@minInitialArmy?: number;}-/** Borrowed during immediate delivery; retainGeneratedDamage owns delayed state. */+/** Immediate generation borrows scratch; captured generation owns its factors and static terms. */export interface GeneratedDamage {factors?: Float64Array;recording: DamageJobRecorder;armyTerm: number;damageBeforeOffsets: number;healthFactor: number;+ capturedDealerFactor?: number;+ capturedTakerFactor?: number;}export function generateDamageJob(@@ -159,17 +161,75 @@};}+/** Snapshot source/static/turn-based contributions; attack-limited taker modifiers wait for landing. */+export function generateCapturedDamageJob(+ job: DamageJob,+ fighters: Record<SideId, ResolvedFighter>,+ options: DamageJobOptions+): GeneratedDamage {+ const recording = options.recorder.startDamageJob();+ const buckets = options.scratch ? resetDamageScratch(options.scratch) : createNumericDamageBuckets();+ const usedEffects = options.usedEffects ?? [];+ const armyTerm = populateSourceBuckets(job, fighters, options, buckets);+ applyPartitionedBucketEffects(job, options.effectIndex, buckets, recording, usedEffects, options.primaryUsedEffects ?? usedEffects, false);+ const capturedDealerFactor = bucketSetValue(options.staticDamageProfile[job.dealerSide][job.dealerUnit].dealerFactor);+ const capturedTakerFactor = bucketSetValue(options.staticDamageProfile[job.takerSide][job.takerUnit].takerFactor);+ const expression = DYNAMIC_EXPRESSIONS[job.kind];+ const damageBeforeOffsets = multiplySlots(1, buckets.factors, expression.numeratorSlots) /+ multiplySlots(1, buckets.factors, expression.denominatorSlots) *+ capturedDealerFactor * capturedTakerFactor * bucketSetValue(DAMAGE_SCALE_BUCKET);+ return {+ factors: options.scratch ? buckets.factors.slice() : buckets.factors,+ recording,+ armyTerm,+ damageBeforeOffsets,+ healthFactor: dynamicHealthFactor(buckets.factors),+ capturedDealerFactor,+ capturedTakerFactor+ };+}++/** Add current taker attack budgets to the original buckets, then settle current shields and caps. */+export function deliverCapturedDamageJob(+ job: DamageJob,+ generated: GeneratedDamage,+ options: DamageJobOptions+): DamageResult {+ const buckets = options.scratch ? resetDamageScratch(options.scratch) : createNumericDamageBuckets();+ buckets.factors.set(generated.factors!);+ const usedEffects = options.usedEffects ?? [];+ applyPartitionedBucketEffects(job, options.effectIndex, buckets, generated.recording, usedEffects, options.primaryUsedEffects ?? usedEffects, true);+ const expression = DYNAMIC_EXPRESSIONS[job.kind];+ // Re-evaluate, rather than dividing by captured factors: a captured bucket may be zero.+ const damageBeforeOffsets = multiplySlots(1, buckets.factors, expression.numeratorSlots) /+ multiplySlots(1, buckets.factors, expression.denominatorSlots) *+ generated.capturedDealerFactor! * generated.capturedTakerFactor! * bucketSetValue(DAMAGE_SCALE_BUCKET);+ return finishDamageJob(job, generated, options, buckets, damageBeforeOffsets, dynamicHealthFactor(buckets.factors));+}+export function deliverDamageJob(job: DamageJob,generated: GeneratedDamage,options: DamageJobOptions): DamageResult {- const { recording, armyTerm, damageBeforeOffsets, healthFactor } = generated;+ const { damageBeforeOffsets, healthFactor } = generated;const buckets = options.scratch ?? createNumericDamageBuckets();if (generated.factors !== buckets.factors) {resetDamageScratch(buckets);if (generated.factors) buckets.factors.set(generated.factors);}+ return finishDamageJob(job, generated, options, buckets, damageBeforeOffsets, healthFactor);+}++function finishDamageJob(+ job: DamageJob,+ generated: GeneratedDamage,+ options: DamageJobOptions,+ buckets: NumericDamageBuckets,+ damageBeforeOffsets: number,+ healthFactor: number+): DamageResult {+ const { recording, armyTerm } = generated;const usedEffects = options.usedEffects ?? [];const primaryUsedEffects = options.primaryUsedEffects ?? usedEffects;const offsetDamage = applyShields(job, options.effectIndex, buckets, recording, damageBeforeOffsets, healthFactor, usedEffects, primaryUsedEffects);@@ -188,15 +248,7 @@usedEffects: ActiveEffect[],primaryUsedEffects: ActiveEffect[]): number {- // Fractional casualties carry between rounds, but every positive remainder is- // still one living troop and contributes fully to the next attack.- const dealerTroops = ceilIgnoringFloatResidue(- Math.max(0, job.roundStartTroops[job.dealerSide][job.dealerUnit] ?? 0)- );- const initialArmy = options.minInitialArmy ?? minInitialArmy(fighters);- const armyTerm = Math.sqrt(dealerTroops) * Math.sqrt(initialArmy);- applyDynamicDamageBucketValue(buckets, "troops.count", armyTerm);- applyDynamicDamageBucketValue(buckets, "source.multiplier", job.sourceMultiplier ?? 1);+ const armyTerm = populateSourceBuckets(job, fighters, options, buckets);const jobSlot = damageJobSlot(job);applyBucketEffects(@@ -212,6 +264,47 @@return armyTerm;}+function populateSourceBuckets(+ job: DamageJob,+ fighters: Record<SideId, ResolvedFighter>,+ options: DamageJobOptions,+ buckets: NumericDamageBuckets+): number {+ // Fractional casualties carry between rounds, but every positive remainder is+ // still one living troop and contributes fully to the next attack.+ const dealerTroops = ceilIgnoringFloatResidue(+ Math.max(0, job.roundStartTroops[job.dealerSide][job.dealerUnit] ?? 0)+ );+ const initialArmy = options.minInitialArmy ?? minInitialArmy(fighters);+ const armyTerm = Math.sqrt(dealerTroops) * Math.sqrt(initialArmy);+ applyDynamicDamageBucketValue(buckets, "troops.count", armyTerm);+ applyDynamicDamageBucketValue(buckets, "source.multiplier", job.sourceMultiplier ?? 1);+ return armyTerm;+}++function dynamicHealthFactor(factors: Float64Array): number {+ return factors[DYNAMIC_BUCKET_INDEX["active.hero.health.up"]] *+ factors[DYNAMIC_BUCKET_INDEX["active.troop.health.up"]] /+ factors[DYNAMIC_BUCKET_INDEX["active.hero.health.down"]] /+ factors[DYNAMIC_BUCKET_INDEX["active.troop.health.down"]];+}++function applyPartitionedBucketEffects(+ job: DamageJob,+ index: EffectIndex,+ buckets: NumericDamageBuckets,+ recording: DamageJobRecorder,+ usedEffects: ActiveEffect[],+ primaryUsedEffects: ActiveEffect[],+ attackLimitedTakerModifier: boolean+): void {+ const jobSlot = damageJobSlot(job);+ for (const group of index.damageGroupsByJobShape[jobSlot]) {+ if (group.attackLimitedTakerModifier !== attackLimitedTakerModifier) continue;+ applyEffectGroup(group, index.liveEffectsByGroup, job.round, jobSlot, buckets, recording, usedEffects, primaryUsedEffects, attackLimitedTakerModifier);+ }+}+function applyBucketEffects(groups: ActiveEffectGroup[],@@ -236,10 +329,11 @@buckets: NumericDamageBuckets,recording: DamageJobRecorder,usedEffects: ActiveEffect[],- primaryUsedEffects: ActiveEffect[]+ primaryUsedEffects: ActiveEffect[],+ attackLimitedTakerModifier?: boolean): void {const dependency = group.requiredGroupOrdinalsByJobShape;- if (dependency && !requiredEffectIsApplicable(dependency, liveEffectsByGroup, round, jobSlot)) return;+ if (dependency && !requiredEffectIsApplicable(dependency, liveEffectsByGroup, round, jobSlot, attackLimitedTakerModifier)) return;const effects = liveEffectsByGroup[group.ordinal];if (effects.length === 0) return;if (group.sameEffectStacking !== "max") {@@ -323,12 +417,15 @@dependency: Array<number[] | undefined>,liveEffectsByGroup: ActiveEffect[][],round: number,- jobSlot: number+ jobSlot: number,+ attackLimitedTakerModifier?: boolean): boolean {const requiredOrdinals = dependency[jobSlot];if (!requiredOrdinals) return false;for (const ordinal of requiredOrdinals) {for (const effect of liveEffectsByGroup[ordinal]) {+ if (attackLimitedTakerModifier !== undefined &&+ effect.effectGroup!.attackLimitedTakerModifier !== attackLimitedTakerModifier) continue;if (isEffectAttackReady(effect) && effect.getCurrentValue(round) !== 0) return true;}}diff --git a/simulator/src/effectIndex.test.ts b/simulator/src/effectIndex.test.ts--- a/simulator/src/effectIndex.test.ts+++ b/simulator/src/effectIndex.test.ts@@ -122,6 +122,7 @@group = {ordinal: groups.length,bucketIndex: 0,+ attackLimitedTakerModifier: false,sameEffectStacking: effect.sameEffectStacking};byResolvedGroup.set(key, group);diff --git a/simulator/src/extraAttacks.ts b/simulator/src/extraAttacks.ts--- a/simulator/src/extraAttacks.ts+++ b/simulator/src/extraAttacks.ts@@ -9,7 +9,14 @@} from "./types";import { UNIT_TYPES, unitMaskHas, unitsFromMask } from "./types";import { advanceEffectAttackDelay } from "./effects";-import { generateDamageJob, deliverDamageJob, retainGeneratedDamage, ceilIgnoringFloatResidue, type DamageJobOptions } from "./damage";+import {+ generateDamageJob,+ deliverDamageJob,+ generateCapturedDamageJob,+ deliverCapturedDamageJob,+ ceilIgnoringFloatResidue,+ type DamageJobOptions+} from "./damage";import { normalizeUnitType } from "./normalize";import {capJobToRemainingTarget,@@ -23,14 +30,14 @@type Runtime} from "./runtime";-// Spawn, calculate, and charge extra attacks riding on one normal attack.-// Returns the finalized kills from every generated job in this normal attack's-// cluster. A triggered child can instead carry damage captured in an earlier round;-// shields are settled only when the child's locked normal attack matches.+// Pending jobs land before the matching normal attack is declared; immediate jobs+// run after its damage. Each effect participates in only one phase, so its attack+// delay advances once per matching normal attack. Only immediate skill kills feed+// that normal attack's deferred formulas.// The effect is charged one use only when at least one of its own jobs actually ran.-// Spawning reads only round-start state and the effect's own gates, so running earlier-// effects' jobs first cannot change what later effects spawn.+// Snapshot eligible effects before delivery because charging may expire them.export function processExtraAttacks(+ phase: "pending" | "immediate",normalAttack: DamageJob,intent: AttackIntent,runtime: Runtime,@@ -47,23 +54,32 @@let skillKills = 0;// Snapshot the applicable effects: charging an effect below may expire it out of the live index.const effects = runtime.effectIndex.extraAttacks.filter(- (effect) => extraAttackEffectAppliesToNormalAttack(effect, normalAttack) && advanceEffectAttackDelay(effect)+ (effect) =>+ (phase === "pending" ? (effect.pendingDamageJobs?.length ?? 0) > 0 : effect.pendingDamageJobs === undefined) &&+ extraAttackEffectAppliesToNormalAttack(effect, normalAttack) &&+ advanceEffectAttackDelay(effect));for (const effect of effects) {const sourceEffectId = effect.source.effectId ?? effect.intent.id;let processedJobCount = 0;let firstProcessedJob: DamageJob | undefined;if (effect.pendingDamageJobs) {- for (const pending of effect.pendingDamageJobs) {+ const pendingJobs = effect.pendingDamageJobs;+ let retainedJobCount = 0;+ for (const pending of pendingJobs) {const deliveryJob: DamageJob = {...pending.job,round,calculationRound: pending.job.round,roundStartTroops};- if (loopOptions.capRoundKills && targetExhausted(deliveryJob, roundStartTroops, roundTargetDamage)) continue;+ if (loopOptions.capRoundKills && targetExhausted(deliveryJob, roundStartTroops, roundTargetDamage)) {+ pendingJobs[retainedJobCount++] = pending;+ continue;+ }recorder.recordScheduledDamageJob(deliveryJob);- const result = deliverDamageJob(deliveryJob, pending.generated, damageJobOptions);+ const result = deliverCapturedDamageJob(deliveryJob, pending.generated, damageJobOptions);+ if (deliveryJob.kind === "skill") recorder.recordSkillDamageJob(deliveryJob, effect);if (loopOptions.capRoundKills) {capJobToRemainingTarget(result, deliveryJob, roundStartTroops, roundTargetDamage, recorder);} else if (loopOptions.capJobKills) {@@ -75,10 +91,15 @@}results.push({ job: deliveryJob, result, intent });totalKills += result.kills;+ if (deliveryJob.kind === "skill") {+ skillKills += result.kills;+ runtime.extraSkillAttackJobsByEffect[sourceEffectId] = (runtime.extraSkillAttackJobsByEffect[sourceEffectId] ?? 0) + 1;+ }processedJobCount += 1;firstProcessedJob ??= deliveryJob;chargeUsedEffectsForJob(runtime, deliveryJob, recorder);}+ pendingJobs.length = retainedJobCount;} else {for (const definition of effect.triggerDamageJobs ?? []) {const sources = resolveTriggerJobSelector(definition.source, "source", effect, normalAttack, roundStartTroops);@@ -161,7 +182,7 @@sourceEffectId: effect.source.effectId ?? effect.intent.id,sourceMultiplier: multiplier};- const generated = retainGeneratedDamage(generateDamageJob(job, fighters, damageJobOptions));+ const generated = generateCapturedDamageJob(job, fighters, damageJobOptions);pending.push({ job, generated });chargeUsedEffectsForJob(runtime, job, damageJobOptions.recorder);}diff --git a/simulator/src/runtimeSkills.ts b/simulator/src/runtimeSkills.ts--- a/simulator/src/runtimeSkills.ts+++ b/simulator/src/runtimeSkills.ts@@ -142,7 +142,9 @@const group: ActiveEffectGroup = {ordinal: effectGroups.length,bucketIndex: damageBucketIndex(definition.name),- sameEffectStacking: effect.sameEffectStacking+ sameEffectStacking: effect.sameEffectStacking,+ attackLimitedTakerModifier: effect.kind === "modifier" &&+ effect.duration.attacks !== undefined && definition.jobSide === "taker"};groupMetadata.set(group, {ownerSide: skill.side,diff --git a/simulator/src/simulator.test.ts b/simulator/src/simulator.test.ts--- a/simulator/src/simulator.test.ts+++ b/simulator/src/simulator.test.ts@@ -21,6 +21,71 @@return runPrepared(prepareBattle(input, config), undefined, options);}+test("Gordon suppresses on third turns and boosts normal Lancer damage on the following turns", () => {+ const result = runOnce({+ maxRounds: 7,+ attacker: {+ troops: { lancer_t6: 1000 },+ heroes: { Gordon: { skill_1: 2, skill_2: 2, skill_3: 2 } }+ },+ defender: { troops: { lancer_t6: 1000 } }+ }, loadSimulatorConfig(), { mode: "standard" });++ assert.deepEqual(result.attacks+ .filter((attack) => attack.appliedEffects?.some((effect) => effect.effectId === "ChemicalTerror/1"))+ .map((attack) => attack.round), [4, 7]);+ assert.deepEqual(result.attacks+ .filter((attack) => attack.appliedEffects?.some((effect) => effect.effectId === "ChemicalTerror/2"))+ .map((attack) => attack.round), [3, 6]);+});++test("Gordon boosts Wayne skill damage on Chemical Terror's triggering turn", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/gordon_interactions_20260925/gordon_wayne_1200l_vs_4800l.json", import.meta.url), "utf8"));+ assert.equal(signedRemainingScore(runOnce(input, loadSimulatorConfig())), -313);+});++test("Ahmose Blade of Light deals separate skill damage with Bradley and against Wu Ming", () => {+ const config = loadSimulatorConfig();+ for (const [path, survivors] of [+ ["ahmose_bradley_1000i_vs_3700i", -77],+ ["ahmose_1000i_vs_wuming_1000i", -82]+ ] as const) {+ const [input] = JSON.parse(readFileSync(new URL(`../../testcases/emulator_verified/ahmose_isolation_20260925/${path}.json`, import.meta.url), "utf8"));+ assert.equal(signedRemainingScore(runOnce(input, config)), survivors, path);+ }+});++test("Renee Dreamslice amplifies allied skill damage against the marked target", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/ahmose_gordon_renee/ahmose_renee_vs_jasser_mark_kind.json", import.meta.url), "utf8"));+ assert.equal(signedRemainingScore(runOnce(input, loadSimulatorConfig())), 937);+});++test("Renee's captured Dream Mark survives the loss of its Lancer source", () => {+ const [input] = JSON.parse(readFileSync(new URL("../../testcases/emulator_verified/renee_isolation_20260925/renee_mark_source_death.json", import.meta.url), "utf8"));+ assert.equal(signedRemainingScore(runOnce(input, loadSimulatorConfig())), 184);+});++test("Dream Mark capture leaves next-hit vulnerability for Marksmen and delivery precedes the next ordinary attack", () => {+ const input: BattleInput = {+ maxRounds: 3,+ attacker: {+ troops: { lancer_t6: 100000, marksman_t6: 100000 },+ heroes: { Renee: { skill_1: 4 }, Gwen: { skill_1: 3 } }+ },+ defender: { troops: { infantry_t6: 1000000 }, heroes: {} }+ };+ const result = runOnce(input, loadSimulatorConfig(), { mode: "trace" });+ const marksmanHit = result.attacks.find(attack =>+ attack.round === 2 && attack.dealerSide === "attacker" && attack.dealerUnit === "marksman"+ )!;+ assert.ok(marksmanHit.appliedEffects?.some(effect => effect.effectId === "EagleVision/1"));+ const nextTurn = result.attacks.filter(attack => attack.round === 3 && attack.dealerSide === "attacker");+ assert.equal(nextTurn[0].sourceEffectId, "NightmareTrace/1");+ assert.ok(nextTurn[0].appliedEffects?.some(effect => effect.effectId === "EagleVision/1"));+ assert.equal(nextTurn[1].sourceEffectId, undefined);+ assert.equal(nextTurn[1].appliedEffects?.some(effect => effect.effectId === "EagleVision/1"), false);+});+test("delayed damage settles shields on arrival in recorded Gatot battles", () => {const config = loadSimulatorConfig();for (const [path, survivors] of [diff --git a/simulator/src/simulator.ts b/simulator/src/simulator.ts--- a/simulator/src/simulator.ts+++ b/simulator/src/simulator.ts@@ -299,6 +299,11 @@continue;}+ const pendingAttacks = processExtraAttacks("pending", job, intent, runtime, fighters, damageJobOptions, roundTargetDamage, loopOptions, results);+ if (loopOptions.scoreSide && job.dealerSide === loopOptions.scoreSide.dealerSide && job.takerSide === loopOptions.scoreSide.takerSide) {+ score += pendingAttacks.totalKills;+ }+const matchingTriggerSkills = runtime.skills.attackDeclaredByJobShape[damageJobShapeSlot("normal", intent.dealerSide, intent.dealerUnit, intent.takerSide, intent.takerUnit)];@@ -328,7 +333,7 @@captureTriggeredExtraDamage(triggeredChildren, job, fighters, damageJobOptions, runtime);advanceNormalAttackCounters(intent, runtime);- const extraAttacks = processExtraAttacks(job, intent, runtime, fighters, damageJobOptions, roundTargetDamage, loopOptions, results);+ const extraAttacks = processExtraAttacks("immediate", job, intent, runtime, fighters, damageJobOptions, roundTargetDamage, loopOptions, results);if (loopOptions.scoreSide && job.dealerSide === loopOptions.scoreSide.dealerSide && job.takerSide === loopOptions.scoreSide.takerSide) {score += extraAttacks.totalKills;}diff --git a/simulator/src/types.ts b/simulator/src/types.ts--- a/simulator/src/types.ts+++ b/simulator/src/types.ts@@ -290,6 +290,8 @@ordinal: number;bucketIndex: number;sameEffectStacking: SameEffectStacking;+ /** Taker-side attack budgets are sampled when captured damage lands, not when it is generated. */+ attackLimitedTakerModifier: boolean;// Prepared dependency lookup indexed by damage-job shape. An empty slot means the// required effect cannot apply to that job, so this group must not contribute.requiredGroupOrdinalsByJobShape?: Array<number[] | undefined>;
Run B dirty state patch
diff --git a/testcases/emulator_verified/attdef_test_minxxx_attacks_nc.json b/testcases/emulator_verified/attdef_test_minxxx_attacks_nc.json--- a/testcases/emulator_verified/attdef_test_minxxx_attacks_nc.json+++ b/testcases/emulator_verified/attdef_test_minxxx_attacks_nc.json@@ -65,7 +65,7 @@},"mark": {"attack": 83.3,- "defense": 0.0,+ "defense": 69.9,"lethality": 37.6,"health": 29.4}