# Handoff Report: Milestone M2 Review (Combat Integration, Concurrency & Robustness)

- **Agent**: `reviewer_m2_progression_2`
- **Roles**: reviewer, critic
- **Working Directory**: `c:\Projects\FreeExile\.agents\teamwork\reviewer_m2_progression_2`
- **Recipient**: `orchestrator_4` (`6f4a2aa2-4315-4660-8cb7-8352a7220c95`)
- **Date**: 2026-10-01T03:08:30Z
- **Handoff Type**: Hard
- **Verdict**: **REQUEST_CHANGES**

---

## 1. Observation

1. **Combat Fatal Damage & Hook Inspection**:
   - File `server/world/combat_engine.py:46`: `DamageEventResult` defines `is_fatal: bool = False`.
   - File `server/world/combat_engine.py:73-84`: `attach_progression_service(self, service: Any)` attaches an internal `_hook` to `self.on_fatal_damage`. Zero circular dependencies exist (no imports of `LevelProgressionService` or progression types).
   - Execution performance: Hook runs synchronous in-memory dictionary lookup and arithmetic (< 0.05ms), well below the 25ms SLA.
   - File `server/world/combat_engine.py:175`: `defender.current_hp = max(0.0, defender.current_hp - final_damage)` followed by `is_fatal = (defender.current_hp <= 0.0)`. When tested with a second strike on an already dead actor (`current_hp == 0.0`), `is_fatal` evaluated to `True` again, invoking `apply_death_penalty` twice and resulting in `deaths_count == 2`.
   - File `server/world/combat_engine.py:30, 138-149`: `CombatActor.last_evasion_timestamp_ms` defaults to `0`. An attack resolved at `current_timestamp_ms = 100` resulted in `is_evaded: True`, `final_damage: 0.0` despite `trigger_phantom_evasion()` never being invoked.

2. **Level Progression Service & Death Penalty Inspection**:
   - File `server/world/level_progression_service.py:36`: `self._players: Dict[str, PlayerProgressionState] = {}`. In-memory dictionary without lock. Safe within single-threaded 30Hz zone loop, but prone to lost updates under multi-threaded concurrency.
   - File `server/world/level_progression_service.py:298-300`: `if player.level >= 100: return self._build_death_result(player, 0, 0.0, player.current_exp)`. Tested empirically: `s.apply_death_penalty('p100')` left `deaths_count = 0` and called 0 registered `_death_listeners`.
   - File `server/world/level_progression_service.py:253`: When advancing to Level 100 with excess EXP, `cumulative_exp` is not clamped to `24,285,477,315`, overflowing by the excess EXP amount.
   - File `server/world/level_progression_service.py:151-158`: Tested `base_exp = -50`. Awarded EXP became negative, resulting in `current_exp = -11`.
   - Boundary tests for death penalty:
     - Dying at 0% EXP at Level 95: `exp_lost = 0`, `new_exp = 0`, `de_leveled = False` (PASS).
     - Dying at 10% EXP at Level 99: `exp_lost = initial_exp`, `new_exp = 0`, `de_leveled = False` (PASS).
     - Dying at Levels 1-60: ratio = 0.0, `exp_lost = 0` (PASS).

3. **Automated Verification Command Results**:
   - `pytest tests/unit/test_level_progression_service.py -k "test_combat or test_death"` -> `20 passed, 13 deselected in 0.17s` (Exit 0).
   - `pytest tests/e2e/test_level_progression_e2e.py -v` -> `47 passed, 3 xfailed in 0.38s` (Exit 0).
   - `python tools/security/run_independent_security_audit.py` -> `PASS`, 0 Critical, 0 High vulnerabilities (Exit 0).
   - `python tools/lint/check_code_and_doc_hygiene.py --strict` -> `PASS`, all files conform to Hard Cap (max file 337 lines, 0 functions > 50 lines) (Exit 0).
   - `python -m mypy --explicit-package-bases --follow-imports=silent server/world/level_progression_types.py server/world/level_progression_service.py server/world/combat_engine.py tests/unit/test_level_progression_service.py` -> `Success: no issues found in 4 source files` (Exit 0).

---

## 2. Logic Chain

1. **From Observation 1**:
   `is_fatal` is evaluated as `(defender.current_hp <= 0.0)`. In a game with multi-projectile spells or AoE damage, multiple damage events can hit a character during the same frame or before zone transition. Because `is_fatal` is `True` for every hit while HP is 0, each hit fires `self.on_fatal_damage`, causing `apply_death_penalty()` to execute multiple times for a single character death. This causes players to lose 2x, 3x, or more of the intended death penalty (e.g., losing 50% or 75% at Level 99).
2. **From Observation 1**:
   Because `last_evasion_timestamp_ms` defaults to 0, `0 <= current_timestamp_ms - 0 <= 250` triggers an evasion i-frame during the first 250ms of any simulation run or test case starting at timestamp $\le 250$.
3. **From Observation 2**:
   The early return in `apply_death_penalty()` for `player.level >= 100` prevents updating `deaths_count` and prevents calling `_death_listeners`. Hardcore permadeath monitoring and death telemetry are completely bypassed for Level 100 characters.
4. **From Observation 2**:
   `cumulative_exp` is not clamped to the Level 100 benchmark cap on level-up rollover, directly violating the requirement of zero overflow past Level 100 cumulative EXP.
5. **From Observations 1, 2, 3**:
   Although unit, E2E, hygiene, and security suites pass with zero integrity violations, the four functional defects above compromise game balance, combat fairness, and telemetry accuracy. Therefore, the implementation cannot be approved in its current state.

---

## 3. Caveats

1. **Concurrency Context**: In FreeExile's standard server architecture, Zone Servers execute sequentially on a single-threaded 30Hz event loop (Actor model). Under this model, synchronous in-memory dictionary access is safe from race conditions during a single tick. However, if background worker threads access `LevelProgressionService` concurrently, synchronization locks will be required.
2. **Milestone M3 Scope**: 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 xfailed as expected for Milestone M3.

---

## 4. Conclusion

**Verdict: REQUEST_CHANGES**

The worker must implement the following remediations:
1. **Fix Corpse Overkill in `server/world/combat_engine.py`**:
   Track `was_alive = (defender.current_hp > 0.0)` and set `is_fatal = was_alive and (defender.current_hp <= 0.0)`.
2. **Fix Phantom Evasion in `server/world/combat_engine.py`**:
   Check `if defender.last_evasion_timestamp_ms > 0:` before checking the i-frame elapsed window.
3. **Fix Level 100 Death Handling in `server/world/level_progression_service.py`**:
   Remove early return on line 299 so `deaths_count` increments and `_death_listeners` fire for Level 100 deaths with 0 EXP penalty.
4. **Fix Cumulative EXP Cap in `server/world/level_progression_service.py`**:
   Clamp `cumulative_exp` to `self.get_benchmark(100).cumulative_exp` when `curr_lvl >= 100`.
5. **Sanitize Input in `server/world/level_progression_service.py`**:
   Clamp `raw_exp = max(0, raw_exp)`.

---

## 5. Verification Method

To verify the required fixes once implemented:

1. **Verify Corpse Overkill Fix**:
   ```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')"
   ```

2. **Verify Level 100 Death Listener Fix**:
   ```powershell
   python -c "from server.world.level_progression_service import LevelProgressionService; s = LevelProgressionService(); s.set_player_state('p100', level=100); calls = []; s.add_death_penalty_listener(lambda r: calls.append(r)); s.apply_death_penalty('p100'); assert s.get_level_info('p100').deaths_count == 1, 'deaths_count not incremented!'; assert len(calls) == 1, 'death listener not called!'; print('Level 100 death listener fix VERIFIED')"
   ```

3. **Verify Phantom Evasion Fix**:
   ```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')"
   ```

4. **Run Full Test Suite & Audits**:
   ```powershell
   pytest tests/unit/test_level_progression_service.py -v
   pytest tests/e2e/test_level_progression_e2e.py -v
   python tools/security/run_independent_security_audit.py
   python tools/lint/check_code_and_doc_hygiene.py --strict
   ```
