# Handoff Report: Milestone M2 Iteration 2 Combat Engine Drop-In Fixes

- **Agent**: `explorer_m2_progression_2_gen2`
- **Role**: teamwork_preview_explorer
- **Working Directory**: `c:\Projects\FreeExile\.agents\teamwork\explorer_m2_progression_2_gen2`
- **Recipient**: `orchestrator_4` (`6f4a2aa2-4315-4660-8cb7-8352a7220c95`)
- **Date**: 2026-10-01T03:14:00Z
- **Handoff Type**: Hard

---

## 1. Observation

1. **Corpse Multi-Hit Overkill in `server/world/combat_engine.py:174-175`**:
   - Source code snippet:
     ```python
     174:         defender.current_hp = max(0.0, defender.current_hp - final_damage)
     175:         is_fatal = (defender.current_hp <= 0.0)
     ```
   - Execution command reproducing failure:
     ```powershell
     python -c "from server.world.combat_engine import CombatEngine, CombatActor; from server.world.martial_matrix import FiveElements; from server.world.level_progression_service import LevelProgressionService; s = LevelProgressionService(); s.set_player_state('p_corpse', level=80, current_exp=10000); e = CombatEngine(); e.attach_progression_service(s); a = CombatActor(1, 'M', FiveElements.KIM, base_attack=1000); d = CombatActor(2, 'P', FiveElements.KIM, current_hp=500, is_player=True, player_id='p_corpse'); e.register_actor(a); e.register_actor(d); res1 = e.calculate_damage(1, 2, 1000, FiveElements.KIM, 1000); res2 = e.calculate_damage(1, 2, 1000, FiveElements.KIM, 1200); assert s.get_level_info('p_corpse').deaths_count == 1, 'Corpse overkill triggered duplicate penalty!'; print('Corpse overkill fix VERIFIED')"
     ```
   - Verbatim output:
     ```text
     Traceback (most recent call last):
       File "<string>", line 1, in <module>
     AssertionError: Corpse overkill triggered duplicate penalty!
     ```

2. **Phantom Evasion at Encounter Start in `server/world/combat_engine.py:30, 138-140`**:
   - Source code snippet:
     ```python
     30:     last_evasion_timestamp_ms: int = 0
     ...
     138:         elapsed = current_timestamp_ms - defender.last_evasion_timestamp_ms
     139:         if 0 <= elapsed <= defender.evasion_iframe_duration_ms:
     140:             return DamageEventResult(..., is_evaded=True, ...)
     ```
   - Execution command reproducing failure:
     ```powershell
     python -c "from server.world.combat_engine import CombatEngine, CombatActor; from server.world.martial_matrix import FiveElements; e = CombatEngine(); a = CombatActor(1, 'M', FiveElements.KIM, base_attack=100); d = CombatActor(2, 'P', FiveElements.KIM, current_hp=500); e.register_actor(a); e.register_actor(d); res = e.calculate_damage(1, 2, 100, FiveElements.KIM, current_timestamp_ms=100); assert res.is_evaded is False, 'Phantom evasion triggered at timestamp 100ms!'; print('Phantom evasion fix VERIFIED')"
     ```
   - Verbatim output:
     ```text
     Traceback (most recent call last):
       File "<string>", line 1, in <module>
     AssertionError: Phantom evasion triggered at timestamp 100ms!
     ```

3. **Challenger Harness Execution (`challenge_combat_progression.py`)**:
   - Command:
     ```powershell
     python .agents/teamwork/challenger_m2_progression_2/challenge_combat_progression.py
     ```
   - Verbatim failure:
     ```text
     VULNERABILITY [HIGH/CRITICAL]: Corpse Multi-Hit EXP Duplication! Striking dead goblin (HP=0) awarded additional 25 EXP (Total: 25 -> 50).
     VULNERABILITY [HIGH]: Multi-Hit Channeled Death Penalty Drain! Player struck 3 times by same barrage suffered 3 deaths, losing 45% EXP instead of 15%.
     CHALLENGER VERDICT: REQUEST_CHANGES (Exit Code 1)
     ```

4. **Line and Function Metric Observations**:
   - File `server/world/combat_engine.py`: 192 total lines.
   - Longest function: `calculate_damage` (41 lines), followed by `_check_special_damage_cases` (35 lines).
   - With proposed drop-in changes: total lines = 195 lines (<= 350 soft cap, <= 500 hard cap), max function length = 43 lines (<= 50 lines hard cap).

---

## 2. Logic Chain

1. **From Observation 1**: In `calculate_damage()`, `is_fatal` is assigned strictly as `(defender.current_hp <= 0.0)`. When an actor's HP is already `0.0`, any subsequent hit yields `0.0 <= 0.0`, which evaluates to `True`. Because `on_fatal_damage` executes on any hit where `is_fatal is True`, subsequent hits on dead corpses fire fatal callbacks repeatedly.
2. Therefore, capturing prior state `was_alive = (defender.current_hp > 0.0)` before damage subtraction, and evaluating `is_fatal = was_alive and (new_hp <= 0.0)`, guarantees that once an actor is at 0 HP, subsequent hits evaluate to `is_fatal = False` and completely skip fatal hooks.
3. **From Observation 2**: `CombatActor.last_evasion_timestamp_ms` was initialized to `0`. When combat begins at timestamp 0 or any timestamp $\le 250\text{ ms}$, `elapsed = current_timestamp_ms - 0` satisfies $0 \le \text{elapsed} \le 250$, falsely granting 250ms of dodge i-frames without the player or monster ever executing Huyễn Ảnh Bộ.
4. Setting `last_evasion_timestamp_ms: int = -1000` (or checking `if defender.last_evasion_timestamp_ms >= 0:`) guarantees that until `trigger_phantom_evasion()` is called, no evasion window can ever be active at encounter start.
5. **From Observation 3**: When both drop-in fixes are combined with the Level 100 listener fix in `server/world/level_progression_service.py` (removing early return at lines 298-299), all 6 challenge suites pass with `CHALLENGER VERDICT: APPROVE` (Exit Code 0).
6. **From Observation 4**: The proposed edits add exactly 3 net lines to `combat_engine.py`, preserving strict compliance with the project's length thresholds (soft cap <= 350 lines, functions <= 50 lines).

---

## 3. Caveats

1. **Read-Only Scope**: In adherence to the Teamwork Explorer archetype and dispatch directive, this agent did not modify production files (`server/world/combat_engine.py` or `server/world/level_progression_service.py`). The fixes were validated using monkey-patched test harness `verify_drop_in_fixes.py` located in this agent's folder.
2. **Actor ID Types**: In `CombatActor`, `actor_id` is typed as `int`, while `player_id` is an `Optional[str]`. The hook logic in `attach_progression_service` safely falls back to `str(atk.actor_id)` or `str(dfn.actor_id)` if `player_id` is not explicitly set.
3. **Ascendancy M3 Tests**: Tests `test_f06_trial_10_rejected_at_level_99`, `test_f06_trial_10_accepted_at_level_100`, and `test_f07_godhood_keystone_metamorphosis_flag` remain marked `xfail` in `tests/e2e/test_level_progression_e2e.py` as they belong to Milestone M3 scope.

---

## 4. Conclusion

The exact drop-in changes required for `server/world/combat_engine.py` are fully formulated, verified, and ready for immediate application by the implementation worker (`worker_m2_progression_2_gen2`):

1. **In `CombatActor` (line 30)**:
   Change `last_evasion_timestamp_ms: int = 0` to `last_evasion_timestamp_ms: int = -1000`.
2. **In `_check_special_damage_cases` (line 138)**:
   Wrap elapsed calculation in `if defender.last_evasion_timestamp_ms >= 0:`.
3. **In `calculate_damage` (line 174)**:
   Add `was_alive = (defender.current_hp > 0.0)` before damage calculation, update `defender.current_hp = new_hp`, and set `is_fatal = was_alive and (new_hp <= 0.0)`.
4. **Accompanying fix in `server/world/level_progression_service.py` (lines 298-299)**:
   Remove early return on `player.level >= 100` so `deaths_count` increments and `_death_listeners` fire on Level 100 character death.

---

## 5. Verification Method

Once the implementer applies the changes, the following commands will independently verify the fixes:

1. **Verify Corpse Overkill & Phantom Evasion**:
   ```powershell
   python -c "from server.world.combat_engine import CombatEngine, CombatActor; from server.world.martial_matrix import FiveElements; e = CombatEngine(); a = CombatActor(1, 'M', FiveElements.KIM, base_attack=100); d = CombatActor(2, 'P', FiveElements.KIM, current_hp=500); e.register_actor(a); e.register_actor(d); res = e.calculate_damage(1, 2, 100, FiveElements.KIM, current_timestamp_ms=100); assert res.is_evaded is False; print('Phantom evasion fix VERIFIED')"
   ```
   ```powershell
   python -c "from server.world.combat_engine import CombatEngine, CombatActor; from server.world.martial_matrix import FiveElements; from server.world.level_progression_service import LevelProgressionService; s = LevelProgressionService(); s.set_player_state('p_corpse', level=80, current_exp=10000); e = CombatEngine(); e.attach_progression_service(s); a = CombatActor(1, 'M', FiveElements.KIM, base_attack=1000); d = CombatActor(2, 'P', FiveElements.KIM, current_hp=500, is_player=True, player_id='p_corpse'); e.register_actor(a); e.register_actor(d); res1 = e.calculate_damage(1, 2, 1000, FiveElements.KIM, 1000); res2 = e.calculate_damage(1, 2, 1000, FiveElements.KIM, 1200); assert s.get_level_info('p_corpse').deaths_count == 1; assert res1.is_fatal is True; assert res2.is_fatal is False; print('Corpse overkill fix VERIFIED')"
   ```

2. **Run Empirical Challenger Suite**:
   ```powershell
   python .agents/teamwork/challenger_m2_progression_2/challenge_combat_progression.py
   ```
   *Expected output*: `CHALLENGER VERDICT: APPROVE` (Exit code 0).

3. **Run Full Progression and Combat Unit/E2E Tests**:
   ```powershell
   pytest tests/unit/test_level_progression_service.py tests/e2e/test_poe2_zone_and_encounter_e2e.py tests/e2e/test_level_progression_e2e.py -v
   ```

4. **Verify Strict Hygiene and Typing**:
   ```powershell
   python -m mypy --explicit-package-bases --follow-imports=silent server/world/combat_engine.py
   python tools/lint/check_code_and_doc_hygiene.py --strict
   ```
