# Milestone 3 Remediation (Iteration 2): Client Script Integration & ES Module Loading Report

> **Author**: `teamwork_preview_explorer` (`explorer_m3_r2_1`)  
> **Milestone**: Milestone 3 Remediation (Client Script Integration & ES Wiring)  
> **Target**: Orchestrator (`orchestrator_1`), Parent (`bc45a740-aa86-45b5-8706-381960281bc6`), Downstream Worker (`worker_m3_2`)  
> **Status**: Complete — Ready for Downstream Worker Execution  
> **Patch Artifact**: `file:///c:/Projects/FreeExile/.agents/teamwork/explorer_m3_r2_1/client_script_integration.patch`

---

## 1. Observation

### 1.1. Missing Script Invocations in `client/webapp/index.html`
In `client/webapp/index.html` (lines 132–177), scripts are loaded sequentially:
```html
132:   <!-- FreeExile Modularized Engine & UI Scripts (Tam Phân Lập Native ES Architecture) -->
133:   <script src="js/data/i18n_catalog.js"></script>
134:   <script src="js/data/i18n.js"></script>
135:   <script src="js/data/monster_catalog.js"></script>
136:   <script src="js/engine/iso_math.js"></script>
137:   <script src="js/engine/collision_engine.js"></script>
138:   <script src="js/engine/joystick.js"></script>
139:   <script type="module" src="js/audio/sfx_engine.js"></script>
140:   <script src="js/engine/audio_haptics.js"></script>
141:   <script src="js/engine/loot_filter.js"></script>
142:   <script src="js/engine/monster_loot_dropper.js"></script>
143:   <script src="js/engine/combat_skills.js"></script>
144:   <script src="js/engine/monster_system.js"></script>
145:   <script src="js/engine/world_renderer.js"></script>
146:   <script src="js/engine/vfx_renderer.js"></script>
147:   <script src="js/engine/animation_engine.js"></script>
148:   <script src="js/engine/entity_renderer.js"></script>
149:   <script src="js/engine/canvas_renderer.js"></script>
...
176:   <script type="module" src="js/main.js"></script>
```
**Direct Observation**:
1. `client/webapp/js/data/wilderness_zone_packs.js`, `client/webapp/js/engine/monster_pack_system.js`, and `client/webapp/js/engine/ambush_trigger_system.js` exist on disk but are **completely absent** from `index.html`.
2. Inspecting `client/webapp/js/main.js` (lines 1–227) confirms **zero `import` statements** for any of these three modules.
3. Only Node-based test files (`tests/security_fuzzing/test_wilderness_encounters_adversarial.py` and `test_pack_affixes_and_auras_adversarial.py`) imported them into isolated headless runners, creating a false impression of full implementation.

### 1.2. Runtime Degradation & Silent Fallback in `monster_system.js`
In `client/webapp/js/engine/monster_system.js`:
- Lines 77–80:
```javascript
77:   } else if (typeof window.getWildernessZoneMonsters === 'function') {
78:     activeMonsters.push(...window.getWildernessZoneMonsters(z, createMonsterEntity));
79:     if (typeof window.initZoneAmbushTriggers === 'function') window.initZoneAmbushTriggers(z);
80:   } else if (z === 'zone_tang_kiem_nhai') {
81:     activeMonsters.push(createMonsterEntity({ id: 'pack_hound_1', ...(MONSTER_TEMPLATES.mob_starter_hound || MONSTER_TEMPLATES.mob_feral_hellhound), wx: 2.2, wy: -0.8 }));
...
85:   } else {
86:     activeMonsters.push(createMonsterEntity({ id: 'wild_cannibal_1', ...MONSTER_TEMPLATES.mob_primal_cannibal, wx: 2.5, wy: -1.2 }));
```
- Lines 159–160:
```javascript
159:   if (typeof window.updateMonsterPackAI === 'function') window.updateMonsterPackAI(activeMonsters, dt);
160:   if (typeof window.updateAmbushTriggers === 'function') window.updateAmbushTriggers(dt, activeMonsters, createMonsterEntity);
```
Because neither module loaded in the browser, `window.getWildernessZoneMonsters`, `window.initZoneAmbushTriggers`, `window.updateMonsterPackAI`, and `window.updateAmbushTriggers` evaluated to `undefined`. The browser runtime silently fell back to 3–4 static legacy mobs without packs, leaders, or ambush triggers.

### 1.3. Line Count and Hygiene Metrics for `index.html`
- Current line count of `client/webapp/index.html`: **179 lines**.
- Verified against test suite: `pytest tests/unit/test_webapp_dynamic_templates.py` passed 9/9 in 0.88s.
  - `test_01_index_html_line_count_and_caps`: `self.assertLessEqual(line_count, 200)` (Soft Cap) and `self.assertLessEqual(line_count, 400)` (Hard Cap).
- Adding 3 script tags expands `index.html` from 179 to **182 lines**.
- 182 lines leaves **18 lines of headroom** under the 200-line Soft Cap and **218 lines of headroom** under the 400-line Hard Cap.

---

## 2. Logic Chain

1. **Disconnected Files**: `wilderness_zone_packs.js`, `monster_pack_system.js`, and `ambush_trigger_system.js` use ES module syntax (`export const`, `export function`, `import ...`). When neither `index.html` nor `main.js` references them, modern browsers will never fetch or execute them.
2. **Global Window Bridges Unset**: The three files contain defensive window bridges (`window.getWildernessZoneMonsters`, `window.initZoneAmbushTriggers`, `window.updateMonsterPackAI`, `window.updateAmbushTriggers`, `window.renderLeaderAuraDecal`). Without script execution, these globals remain `undefined`.
3. **Silent Fallback Masks Defect**: `monster_system.js` was written defensively to check `typeof window.getWildernessZoneMonsters === 'function'`. When `undefined`, it silently routes to legacy fallback mobs without throwing runtime exceptions, deceiving developers into thinking monster spawning works.
4. **Script Tag Formulation**: Adding `<script type="module" src="...">` tags for all three files directly in `client/webapp/index.html` immediately after `monster_system.js` (line 144) ensures:
   - Browsers register the ES modules and execute their window bridges.
   - ES module dependency resolution handles `import { isSafeHavenZone, getWildernessPacks } from '../data/wilderness_zone_packs.js'` cleanly.
   - Any zone transition (via `teleportToZone`) triggers `window.getWildernessZoneMonsters` and `window.initZoneAmbushTriggers`.
   - Every tick triggers `window.updateMonsterPackAI` and `window.updateAmbushTriggers`.
5. **Strict Constraint Preservation**: 179 lines + 3 lines = 182 lines, fully preserving both the 200-line soft cap and 400-line hard cap.

---

## 3. Caveats

1. **ES Module Deferral**: In HTML5, `<script type="module">` tags are deferred by default (executed after document parsing, before `DOMContentLoaded`). `monster_system.js` is a classic script (`<script src="...">`) that executes synchronously during parsing. On initial parse, `monster_system.js` initializes `zone_boundless_sanctuary` (a safe haven with target dummy only). Once parsing finishes, the module scripts load and attach their bridges before any user interaction or zone teleportation. If a user or QA test initializes directly into a wilderness zone on first parse, adding a ready-hook in `monster_pack_system.js` ensures automatic refresh.
2. **Reviewer Findings 2 & 3**: While the primary task is client script integration in `index.html`, the downstream worker must also apply the 2 auxiliary fixes highlighted by `reviewer_m3_2`:
   - Hook `renderLeaderAuraDecal` into `client/webapp/js/engine/entity_renderer.js`.
   - Clear `dev.active_instance_id = None` and pop stale instance sessions in `server/world/hideout_engine.py` when `dev.portals_remaining == 0`.

---

## 4. Conclusion & Actionable Recommendations

### 4.1. Exact Script Tags for `client/webapp/index.html`
Insert the following 3 tags directly after `js/engine/monster_system.js` (between line 144 and 145):

```html
  <script type="module" src="js/data/wilderness_zone_packs.js"></script>
  <script type="module" src="js/engine/monster_pack_system.js"></script>
  <script type="module" src="js/engine/ambush_trigger_system.js"></script>
```

### 4.2. Target Code Context in `client/webapp/index.html`
**Before (lines 142–146)**:
```html
  <script src="js/engine/monster_loot_dropper.js"></script>
  <script src="js/engine/combat_skills.js"></script>
  <script src="js/engine/monster_system.js"></script>
  <script src="js/engine/world_renderer.js"></script>
  <script src="js/engine/vfx_renderer.js"></script>
```

**After (lines 142–149)**:
```html
  <script src="js/engine/monster_loot_dropper.js"></script>
  <script src="js/engine/combat_skills.js"></script>
  <script src="js/engine/monster_system.js"></script>
  <script type="module" src="js/data/wilderness_zone_packs.js"></script>
  <script type="module" src="js/engine/monster_pack_system.js"></script>
  <script type="module" src="js/engine/ambush_trigger_system.js"></script>
  <script src="js/engine/world_renderer.js"></script>
  <script src="js/engine/vfx_renderer.js"></script>
```

### 4.3. Auxiliary Fix 1: Leader Aura Decal in `entity_renderer.js`
In `client/webapp/js/engine/entity_renderer.js`, line 124 (inside `item.type === 'monster'` loop, right after drawing the shadow):
```javascript
          // Render Pack Leader Pulsating Ground Aura Decal (PoE2 Standards)
          if (m.isPackLeader && typeof window.renderLeaderAuraDecal === 'function') {
            window.renderLeaderAuraDecal(ctx, m, mPos.x, mPos.y, (window.gameTimeSec || Date.now() * 0.001));
          }
```

### 4.4. Auxiliary Fix 2: Stale Session Clean-up in `hideout_engine.py`
In `server/world/hideout_engine.py` line 270 & line 314:
```python
    def enter_map_portal(
        self,
        player_id: str,
        portal_index: Optional[int] = None,
        zone_engine: Optional[Any] = None,
    ) -> Tuple[bool, str, Optional[Dict[str, Any]]]:
...
        if dev.portals_remaining == 0:
            if zone_engine is not None and hasattr(zone_engine, "active_instances"):
                zone_engine.active_instances.pop(dev.active_instance_id, None)
            dev.active_instance_id = None
            dev.active_map = None
            msg = f"Đã bước qua cổng #{target_idx + 1}. Đây là CỔNG CUỐI CÙNG (0/6)! Tinh Đồ Nghi đã khép lại."
```

### 4.5. Complete Patch Ready for Worker
A unified patch has been generated and validated:
`file:///c:/Projects/FreeExile/.agents/teamwork/explorer_m3_r2_1/client_script_integration.patch`

---

## 5. Verification Method

To verify these changes independently:

### 5.1. Line Count & Hygiene Gate Verification
```bash
# 1. Verify dynamic templates and HTML line count
pytest tests/unit/test_webapp_dynamic_templates.py -v

# 2. Verify strict project hygiene (0 Hard Cap violations)
python tools/lint/check_code_and_doc_hygiene.py --strict
```
*Expected Result*: All 9 template tests pass. `index.html` line count is exactly 182 lines (<= 200 Soft Cap, <= 400 Hard Cap).

### 5.2. HTML Script Inclusion Audit
```bash
git grep -n "wilderness_zone_packs.js" client/webapp/index.html
git grep -n "monster_pack_system.js" client/webapp/index.html
git grep -n "ambush_trigger_system.js" client/webapp/index.html
```
*Expected Result*: Exactly 1 match per file within lines 144–148 of `index.html`.

### 5.3. Milestone 3 Unit & E2E Test Suite Pass
```bash
# Unit test suite
pytest tests/unit/test_monster_pack_and_affixes.py tests/unit/test_wilderness_encounter_density.py tests/unit/test_ambush_trigger_engine.py tests/unit/test_hideout_engine.py -v

# E2E test suite
pytest tests/e2e/test_poe2_zone_and_encounter_e2e.py -v
```
*Expected Result*: 24/24 unit tests pass, 47/50 E2E tests pass (1 planned xfail, 2 xpass).

### 5.4. Leader Aura Decal Verification
```bash
git grep -n "renderLeaderAuraDecal" client/webapp/js/engine/entity_renderer.js
```
*Expected Result*: At least 1 invocation inside `entity_renderer.js`.
