# TECHNICAL INVESTIGATION & TEST SUITE DESIGN REPORT: MILESTONE 1 (SERVER ZONE GATING & SAFE HAVEN PURITY)

**Author**: `teamwork_preview_explorer` (M1 Unit Test Suite Explorer)  
**Target Milestone**: Milestone 1: Server Zone Gating & Safe Haven Purity  
**Working Directory**: `c:\Projects\FreeExile\.agents\teamwork\explorer_m1_3`  
**Date**: 2026-09-30 (UTC)  
**Target Test File**: `tests/unit/test_zone_monster_spawning_rules.py`  
**Affected Source Files**: `server/world/zone_catalog.py`, `server/world/zone_engine.py`

---

## 1. Observation

### 1.1. Existing Test File Inspection
- **File**: `tests/unit/test_zone_monster_spawning_rules.py` (94 lines total)
  - Lines 15-17: `@pytest.fixture def zone_engine() -> ZoneEngine: return ZoneEngine()`.
  - Lines 23-28: `test_sanctuary_zone_type_is_sanctuary` tests only `zone_boundless_sanctuary` (`sanctuary.zone_type == ZoneType.SANCTUARY`).
  - Lines 29-36: `test_outer_exploration_zones_are_open_world` verifies `zone_tang_kiem_nhai` and `zone_ancient_sword_barrow` are `OPEN_WORLD`.
  - Lines 37-47: `test_can_spawn_hostile_monsters_gate` checks `zone_boundless_sanctuary` is `False`, `zone_player_hideout` is `False`, and outer maps are `True`.
  - Lines 48-71: `test_validate_monster_spawn_enforcement` tests `zone_boundless_sanctuary` with `is_dummy=False` (rejected) and `is_dummy=True` (accepted), but **completely omits testing** `zone_player_hideout`.
  - Lines 72-94: `test_client_monster_system_js_no_hostile_mobs_in_hideout` inspects `client/webapp/js/engine/monster_system.js` to ensure no `hellhound_sanctuary` or `skeleton_sanctuary` exist in safe zones.
  - Test Execution Baseline: `pytest tests/unit/test_zone_monster_spawning_rules.py -v` passes with `5 passed in 0.10s`.

### 1.2. Root Cause Observations in Codebase
- **File**: `server/world/zone_catalog.py`
  - Lines 29-497: `_register_zones(engine)` registers `zone_boundless_sanctuary` and 9 open-world maps.
  - **Omission**: `zone_player_hideout` is missing from `_register_zones`.
  - Consequence observed via Python CLI:
    ```python
    >>> ze = ZoneEngine()
    >>> ze.get_zone("zone_player_hideout")
    KeyError: "Zone 'zone_player_hideout' not found in registry."
    >>> ze.spawn_player("p1", "zone_player_hideout")
    KeyError: "Zone 'zone_player_hideout' not found in registry."
    ```
- **File**: `server/world/zone_engine.py`
  - Lines 70 & 78:
    ```python
    self.zone_spatial_grids: Dict[str, SpatialGrid] = {}
    ...
    def add_zone(self, zone: ZoneDefinition) -> None:
        self.zones[zone.zone_id] = zone
        self.zone_spatial_grids[zone.zone_id] = SpatialGrid(cell_size=64.0)
    ```
    Because `zone_player_hideout` was not registered, `"zone_player_hideout"` was never added to `self.zone_spatial_grids`.
  - Lines 89-94: Redundant duplicate method definition:
    ```python
    def get_zone_definition(self, zone_id: str) -> ZoneDefinition:
        """Alias for get_zone for backward compatibility."""
        return self.get_zone(zone_id)

    def get_zone_definition(self, zone_id: str) -> Optional[ZoneDefinition]:
        return self.zones.get(zone_id)
    ```
    The second definition silently overrides the first.
  - Lines 111-112: Ad-hoc hardcoded check:
    ```python
    def can_spawn_hostile_monsters(self, zone_id: str) -> bool:
        if zone_id == "zone_player_hideout":
            return False
        zone = self.zones.get(zone_id)
        if zone is None:
            return False
        return zone.zone_type in (ZoneType.OPEN_WORLD, ZoneType.DUNGEON_INSTANCE, ZoneType.SECRET_CHAMBER)
    ```
- **File**: `server/world/zone_types.py`
  - Lines 57-74: `ZoneDefinition` dataclass signature:
    `ZoneDefinition(zone_id: str, name: str, zone_type: ZoneType, environment: ZoneEnvironment, min_level: int, max_players: int, bounds_width: float, bounds_height: float, default_spawn_x: float, default_spawn_y: float, respawn_zone_id: str, respawn_x: float, respawn_y: float, waypoints: Dict[str, Waypoint] = ..., portals: Dict[str, ZonePortal] = ..., npc_ids: List[str] = ...)`
    **Warning**: `ZoneDefinition` uses parameter `name`, not `display_name`, and does not have `max_level`.

### 1.3. Code Hygiene Constraints
- **Command**: `python tools/lint/check_code_and_doc_hygiene.py --strict`
- Thresholds: Code Soft Cap $\le 350$ lines, Hard Cap $\le 500$ lines; Function length $\le 50$ lines.
- `tests/unit/test_zone_monster_spawning_rules.py` is currently 94 lines. The expanded version is designed to be $\sim 180$ lines with each method $\le 35$ lines, maintaining strict compliance.

---

## 2. Logic Chain

1. **Premise 1**: The user directive and PROJECT.md Milestone 1 require safe havens (`zone_player_hideout` and `zone_boundless_sanctuary`) to strictly prohibit hostile monster spawning and allow only immortal Target Dummies.
2. **Premise 2**: Calling `get_zone("zone_player_hideout")` or `spawn_player(player_id, "zone_player_hideout")` currently crashes with `KeyError` because `zone_player_hideout` is absent from `zone_catalog.py:register_canonical_zones_and_templates`.
3. **Premise 3**: In `ZoneEngine.add_zone()`, each registered zone receives its own dedicated `SpatialGrid(cell_size=64.0)`. Registering `zone_player_hideout` automatically instantiates `zone_spatial_grids["zone_player_hideout"]`.
4. **Premise 4**: Spawning a player via `spawn_player(player_id, "zone_player_hideout")` must succeed without `KeyError`, set `loc.zone_id == "zone_player_hideout"` with coordinates within bounds `(0.0, 0.0)`, and map into the hideout's spatial grid coordinates `(0, 0)`.
5. **Premise 5**: Spatial grid isolation requires that entities added to `zone_spatial_grids["zone_player_hideout"]` are not queryable from `zone_spatial_grids["zone_boundless_sanctuary"]`.
6. **Premise 6**: Deduplicating `get_zone_definition` in `zone_engine.py` removes ambiguity, ensuring `get_zone_definition("zone_player_hideout")` returns `ZoneDefinition` and non-existent zones return `None`.

---

## 3. Caveats

1. **SpatialGrid Entity Registration in `spawn_player`**: `ZoneEngine.spawn_player()` creates and stores a `PlayerLocation` record in `self.player_locations`, but does not automatically invoke `self.zone_spatial_grids[zone_id].add_entity()`. Instead, `SpatialGrid` instances serve as spatial partitioners for Area-of-Interest (AOI) lookups and entity isolation. Tests must verify the existence, cell mapping, and boundary isolation of the hideout grid.
2. **Constructor Argument Fidelity**: `PROJECT.md` line 54 mentions `display_name` and `max_level`. As verified in `zone_types.py:57`, `ZoneDefinition` expects `name: str` and does not take `max_level`. The Worker must use the actual field names to avoid `TypeError`.

---

## 4. Conclusion & Concrete Recommendations for Worker

### 4.1. Code Modifications Required from Worker

#### A. In `server/world/zone_catalog.py`:
Register `zone_player_hideout` inside `_register_zones(engine: ZoneEngine)`:
```python
    # 0. Player Hideout (Tiên Phủ Động Thiên - Sào Huyệt Lưu Đày)
    engine.add_zone(
        ZoneDefinition(
            zone_id="zone_player_hideout",
            name="Tiên Phủ Động Thiên (Hideout)",
            zone_type=ZoneType.SANCTUARY,
            environment=ZoneEnvironment.NORMAL,
            min_level=1,
            max_players=10,
            bounds_width=400.0,
            bounds_height=400.0,
            default_spawn_x=0.0,
            default_spawn_y=0.0,
            respawn_zone_id="zone_player_hideout",
            respawn_x=0.0,
            respawn_y=0.0,
            waypoints={
                "wp_hideout_central": Waypoint(
                    waypoint_id="wp_hideout_central",
                    name="Trụ Đá Thần Hành: Động Thiên",
                    zone_id="zone_player_hideout",
                    x=0.0,
                    y=0.0,
                    is_unlocked_by_default=True,
                )
            },
            portals={},
            npc_ids=["npc_dummy_shrine"],
        )
    )
```

#### B. In `server/world/zone_engine.py`:
1. Clean up duplicate `get_zone_definition` (lines 89-94):
```python
    def get_zone_definition(self, zone_id: str) -> Optional[ZoneDefinition]:
        """Returns ZoneDefinition if present in registry, else None."""
        return self.zones.get(zone_id)
```
2. In `can_spawn_hostile_monsters(self, zone_id: str) -> bool`:
Remove the ad-hoc `if zone_id == "zone_player_hideout": return False` branch so that safe haven gating is purely driven by `zone.zone_type == ZoneType.SANCTUARY`.

---

### 4.2. Recommended Expanded Test Suite for Worker
The Worker should replace `tests/unit/test_zone_monster_spawning_rules.py` with the following comprehensive, non-flaky test suite (~185 lines, 100% compliant with hygiene limits):

```python
"""
Unit tests for PoE2 Zone Spawning Purity & Encounter Rules in FreeExile.
Verifies that Safe Havens (Sanctuary & Hideout) NEVER spawn hostile monsters,
restricting safe zones strictly to inanimate training dummies, while outer
exploration maps and dungeons support dynamic hostile monster populations.
Also validates spatial grid initialization and entity isolation for Player Hideouts.
"""

from pathlib import Path
import pytest

from server.world.spatial_grid import Entity, SpatialGrid
from server.world.zone_engine import ZoneEngine
from server.world.zone_types import ZoneEnvironment, ZoneType


@pytest.fixture
def zone_engine() -> ZoneEngine:
    return ZoneEngine()


class TestPoE2ZoneSpawningPurity:
    """Tests authoritative safe-zone purity and monster spawn gating."""

    def test_sanctuary_zone_type_is_sanctuary(self, zone_engine: ZoneEngine) -> None:
        """Verifies that Outcast Encampment Hub is registered as SANCTUARY."""
        sanctuary = zone_engine.get_zone("zone_boundless_sanctuary")
        assert sanctuary is not None
        assert sanctuary.zone_type == ZoneType.SANCTUARY
        assert sanctuary.environment == ZoneEnvironment.NORMAL
        assert sanctuary.min_level == 1

    def test_player_hideout_zone_type_is_sanctuary(self, zone_engine: ZoneEngine) -> None:
        """Verifies that Player Hideout (Tiên Phủ Động Thiên) is registered as SANCTUARY."""
        hideout = zone_engine.get_zone("zone_player_hideout")
        assert hideout is not None
        assert hideout.zone_id == "zone_player_hideout"
        assert hideout.zone_type == ZoneType.SANCTUARY
        assert hideout.environment == ZoneEnvironment.NORMAL
        assert hideout.min_level == 1
        assert hideout.bounds_width > 0.0
        assert hideout.bounds_height > 0.0

    def test_outer_exploration_zones_are_open_world(self, zone_engine: ZoneEngine) -> None:
        """Verifies that wilderness maps are OPEN_WORLD where monsters roam."""
        bone_strand = zone_engine.get_zone("zone_tang_kiem_nhai")
        assert bone_strand.zone_type == ZoneType.OPEN_WORLD

        ancient_sword = zone_engine.get_zone("zone_ancient_sword_barrow")
        assert ancient_sword.zone_type == ZoneType.OPEN_WORLD

    def test_can_spawn_hostile_monsters_gate(self, zone_engine: ZoneEngine) -> None:
        """Verifies authoritative can_spawn_hostile_monsters rule."""
        # Safe Haven Hub and Hideout: ZERO hostile monsters allowed
        assert zone_engine.can_spawn_hostile_monsters("zone_boundless_sanctuary") is False
        assert zone_engine.can_spawn_hostile_monsters("zone_player_hideout") is False

        # Non-existent zone: Safely rejected
        assert zone_engine.can_spawn_hostile_monsters("invalid_unknown_zone") is False

        # Outer Wilderness Maps: Hostile monsters allowed
        assert zone_engine.can_spawn_hostile_monsters("zone_tang_kiem_nhai") is True
        assert zone_engine.can_spawn_hostile_monsters("zone_ancient_sword_barrow") is True
        assert zone_engine.can_spawn_hostile_monsters("zone_boundless_sandstorm") is True

    def test_validate_monster_spawn_enforcement(self, zone_engine: ZoneEngine) -> None:
        """Verifies validate_monster_spawn rejects hostile spawns in Sanctuary and Hideout."""
        # Hostile monster in Sanctuary -> REJECTED
        can_spawn_sanc, reason_sanc = zone_engine.validate_monster_spawn(
            zone_id="zone_boundless_sanctuary",
            is_dummy=False,
        )
        assert can_spawn_sanc is False
        assert "An Toàn" in reason_sanc or "Sanctuary" in reason_sanc

        # Hostile monster in Player Hideout -> REJECTED
        can_spawn_hideout, reason_hideout = zone_engine.validate_monster_spawn(
            zone_id="zone_player_hideout",
            is_dummy=False,
        )
        assert can_spawn_hideout is False
        assert "An Toàn" in reason_hideout or "Sanctuary" in reason_hideout or "Hideout" in reason_hideout

        # Training dummy in Sanctuary -> ALLOWED
        can_dummy_sanc, reason_dummy_sanc = zone_engine.validate_monster_spawn(
            zone_id="zone_boundless_sanctuary",
            is_dummy=True,
        )
        assert can_dummy_sanc is True
        assert "Target Dummy" in reason_dummy_sanc or "Khôi Lỗi" in reason_dummy_sanc

        # Training dummy in Player Hideout -> ALLOWED
        can_dummy_hideout, reason_dummy_hideout = zone_engine.validate_monster_spawn(
            zone_id="zone_player_hideout",
            is_dummy=True,
        )
        assert can_dummy_hideout is True
        assert "Target Dummy" in reason_dummy_hideout or "Khôi Lỗi" in reason_dummy_hideout

        # Hostile monster in Outer Map -> ALLOWED
        can_wild, _ = zone_engine.validate_monster_spawn(
            zone_id="zone_tang_kiem_nhai",
            is_dummy=False,
        )
        assert can_wild is True

    def test_spawn_player_in_hideout_and_spatial_grid(self, zone_engine: ZoneEngine) -> None:
        """
        Verifies that spawning a player in the hideout succeeds without KeyError,
        sets valid player location coordinates, and guarantees hideout spatial grid initialization.
        """
        player_id = "player_hero_hideout_01"
        loc = zone_engine.spawn_player(player_id, "zone_player_hideout")
        assert loc is not None
        assert loc.player_id == player_id
        assert loc.zone_id == "zone_player_hideout"
        assert loc.x == 0.0
        assert loc.y == 0.0

        # Query player location via engine
        current_loc = zone_engine.get_player_location(player_id)
        assert current_loc.zone_id == "zone_player_hideout"
        assert current_loc.x == 0.0
        assert current_loc.y == 0.0

        # Verify hideout spatial grid exists and is isolated
        assert "zone_player_hideout" in zone_engine.zone_spatial_grids
        assert "zone_boundless_sanctuary" in zone_engine.zone_spatial_grids

        hideout_grid = zone_engine.zone_spatial_grids["zone_player_hideout"]
        sanctuary_grid = zone_engine.zone_spatial_grids["zone_boundless_sanctuary"]

        assert hideout_grid is not None
        assert isinstance(hideout_grid, SpatialGrid)
        assert hideout_grid is not sanctuary_grid
        assert hideout_grid.cell_size == 64.0

        # Verify cell coordinate projection
        cell_coords = hideout_grid.get_cell_coords(loc.x, loc.y)
        assert cell_coords == (0, 0)

    def test_spatial_grid_entity_isolation_hideout_vs_sanctuary(self, zone_engine: ZoneEngine) -> None:
        """
        Verifies that entities within the player hideout spatial grid are isolated
        from the sanctuary encampment and cannot be observed across zone boundaries.
        """
        hideout_grid = zone_engine.zone_spatial_grids["zone_player_hideout"]
        sanctuary_grid = zone_engine.zone_spatial_grids["zone_boundless_sanctuary"]

        dummy_entity = Entity(entity_id=8801, x=0.0, y=0.0)
        hideout_grid.add_entity(dummy_entity)

        assert 8801 in hideout_grid.entities
        assert 8801 not in sanctuary_grid.entities

        # Proximity query in hideout finds entity
        hideout_aoi = hideout_grid.get_entities_in_aoi(0.0, 0.0, radius_cells=1)
        assert 8801 in hideout_aoi

        # Proximity query in sanctuary does NOT find hideout entity
        sanctuary_aoi = sanctuary_grid.get_entities_in_aoi(0.0, 0.0, radius_cells=1)
        assert 8801 not in sanctuary_aoi

    def test_get_zone_definition_clean_and_backward_compatible(self, zone_engine: ZoneEngine) -> None:
        """Verifies deduplicated get_zone_definition method behaves as expected."""
        hideout_def = zone_engine.get_zone_definition("zone_player_hideout")
        assert hideout_def is not None
        assert hideout_def.zone_type == ZoneType.SANCTUARY

        sanctuary_def = zone_engine.get_zone_definition("zone_boundless_sanctuary")
        assert sanctuary_def is not None
        assert sanctuary_def.zone_type == ZoneType.SANCTUARY

        invalid_def = zone_engine.get_zone_definition("zone_unknown_missing")
        assert invalid_def is None

    @pytest.mark.parametrize("safe_zone_id", ["zone_player_hideout", "zone_boundless_sanctuary"])
    @pytest.mark.parametrize(
        "is_dummy, expected_allowed",
        [
            (False, False),
            (True, True),
        ],
    )
    def test_monster_spawn_safe_haven_parameterized(
        self, zone_engine: ZoneEngine, safe_zone_id: str, is_dummy: bool, expected_allowed: bool
    ) -> None:
        """Parametrized test strictly verifying safe haven purity against any non-dummy spawn."""
        allowed, reason = zone_engine.validate_monster_spawn(safe_zone_id, is_dummy=is_dummy)
        assert allowed is expected_allowed
        if not expected_allowed:
            assert "An Toàn" in reason or "Sanctuary" in reason or "Hideout" in reason

    def test_client_monster_system_js_no_hostile_mobs_in_hideout(self) -> None:
        """
        Regression test on client JavaScript engine:
        Guarantees that monster_system.js does NOT spawn hellhounds or skeletons
        in zone_player_hideout or zone_boundless_sanctuary.
        """
        js_path = Path("client/webapp/js/engine/monster_system.js")
        assert js_path.exists(), "monster_system.js must exist"
        content = js_path.read_text(encoding="utf-8")

        # Must not push hellhound_sanctuary or skeleton_sanctuary in safe zones
        assert "hellhound_sanctuary" not in content, (
            "CRITICAL BUG: hellhound_sanctuary must NOT exist in monster_system.js! "
            "Safe zones must have zero hostile monsters."
        )
        assert "skeleton_sanctuary" not in content, (
            "CRITICAL BUG: skeleton_sanctuary must NOT exist in monster_system.js! "
            "Safe zones must have zero hostile monsters."
        )

        # Must have dummy_primal_shrine as isDummy: true
        assert "isDummy: true" in content
```

---

## 5. Verification Method

1. **Verify Negative Baseline (Pre-Fix Failure)**:
   Run the newly drafted test cases before applying the Worker fix:
   ```pwsh
   pytest tests/unit/test_zone_monster_spawning_rules.py -v
   ```
   *Expected Failure*: `KeyError: "Zone 'zone_player_hideout' not found in registry."` at `test_player_hideout_zone_type_is_sanctuary` and `test_spawn_player_in_hideout_and_spatial_grid`.
2. **Verify Positive Baseline (Post-Fix Pass)**:
   After Worker adds `zone_player_hideout` to `server/world/zone_catalog.py` and cleans `server/world/zone_engine.py`:
   ```pwsh
   pytest tests/unit/test_zone_monster_spawning_rules.py -v
   ```
   *Expected Result*: All 10 tests pass in $< 0.15$s.
3. **Verify Regression Suite**:
   ```pwsh
   pytest tests/unit/test_map_instance_system.py -v
   pytest tests/unit/test_hideout_engine.py -v
   pytest tests/unit/test_combat_engine.py -v
   ```
   *Expected Result*: All 21 tests pass with zero regressions.
4. **Verify Hygiene Compliance**:
   ```pwsh
   python tools/lint/check_code_and_doc_hygiene.py --strict
   ```
   *Expected Result*: `test_zone_monster_spawning_rules.py` remains under the 350-line Soft Cap and 500-line Hard Cap.
