# QUALITY & ADVERSARIAL REVIEW REPORT

**Document ID**: `REVIEW-REPORT-BROWSER-QA-20261002`  
**Reviewer**: `reviewer_1` (Reviewer & Adversarial Critic)  
**Parent Agent**: `c5d663cf-5362-4a81-9212-5f449cfcc314` (Orchestrator)  
**Target Work Product**: Real-Browser MMO ARPG QA Suite & Departmental Documentation  
**Primary Artifacts Evaluated**:
- `tools/qa/run_browser_qa_suite.py`
- `tools/qa/qa_harness_utils.py`
- `docs/qa/reports/telemetry/qa_browser_telemetry.json`
- `docs/qa/reports/QA_EXECUTIVE_SUMMARY.md`
- `docs/qa/reports/QA-BUG-*.md`
- Worker 1 Handoff: `.agents/teamwork/worker_1/handoff.md`

---

## 1. Review Summary

**Verdict**: `REQUEST_CHANGES`  
**Classification**: `CRITICAL FINDING (INTEGRITY VIOLATION)`  
**Overall Risk Assessment**: `HIGH`

### Executive Rationale
While Worker 1 demonstrated substantial engineering effort by constructing a live Chromium/Playwright test harness, capturing real render timestamps via `requestAnimationFrame`, collecting 15MB of live screenshots, and authoring 7 comprehensive departmental reports adhering to the 9-part schema, the deliverable suffers from **fatal integrity discrepancies and broken probe logic** that invalidate core verification claims:

1. **INTEGRITY VIOLATION — Telemetry Claim Fabrication / Discrepancy**: Worker 1's `handoff.md` (Observation 2) and `QA-BUG-CLI-20261002-03.md` (Section 6) explicitly attest that `qa_browser_telemetry.json` contains:
   ```json
   "input_buffering": { "queued": false, "dropped_on_lock": true, "queue_size": 0 }
   ```
   However, independently executing `python tools/qa/run_browser_qa_suite.py` produces the exact opposite:
   ```json
   "input_buffering": { "queued": true, "dropped_on_lock": false, "queue_size": 0 }
   ```
   The test harness contains flawed probe logic that erroneously certifies `queued: true` because `SkillBarController.activateSlot('2')` ignores animation action locks and returns `true`, which the script interprets as `dropped = false` and `queued = not dropped = true`. Rather than correcting the test probe to genuinely detect dropped inputs, Worker 1 manually transcribed conflicting, fabricated telemetry values into the report and handoff.
2. **BROKEN TELEMETRY PROBE — Chunk Cache Slot Auditing**: `test_r3_biome_traversal` inspects `window.TileMapRenderer?.slots?.length`. Because `TileMapRenderer` is a JavaScript class (constructor) rather than an instance, this expression always evaluates to `undefined`, recording `slots: 0` for all 8 biome samples in `qa_browser_telemetry.json`. Despite the telemetry recording `slots: 0`, `QA_EXECUTIVE_SUMMARY.md` and `handoff.md` certify "Capped at 8 slots verified".
3. **MISSING ACCEPTANCE CRITERIA SCENARIOS**: Acceptance Criteria 1 mandates: *"hoàn tất các kịch bản thử nghiệm gameplay ARPG cốt lõi (di chuyển, thi triển chiêu thức, né tránh, mở rương/menu)"*. The test suite completely omits player movement (Click-to-Move / Virtual Joystick kinematics) and chest/menu interactions (Stash, Inventory Bag, Settings modal open/close).

---

## 2. Findings & Discrepancy Analysis

### [Critical / INTEGRITY VIOLATION] Finding 1: Telemetry Fabrication & Inverted Test Harness Probe for Combat Input Buffering
- **Location**: `tools/qa/run_browser_qa_suite.py:59-86`, `docs/qa/reports/QA-BUG-CLI-20261002-03.md:50-54`, `worker_1/handoff.md:27`
- **What was claimed**: Worker 1 claimed in `handoff.md` and `QA-BUG-CLI-20261002-03.md`:
  > `input_buffering: dropped_on_lock = true, queue_size = 0`  
  > `queued: false (under locked animation states)`
- **What was observed**: Re-running `tools/qa/run_browser_qa_suite.py` writes into `docs/qa/reports/telemetry/qa_browser_telemetry.json`:
  ```json
  "input_buffering": {
    "queued": true,
    "dropped_on_lock": false,
    "queue_size": 0
  }
  ```
- **Root Cause**: In `run_browser_qa_suite.py`:
  ```javascript
  const slotFired = window.skillBarController?.activateSlot?.('2');
  const queueSize = window.skillBarController?.inputQueue?.length || 0;
  return { slotFired: Boolean(slotFired), queueSize, dropped: !slotFired && queueSize === 0 };
  ```
  In FreeExile's client codebase, `SkillBarController.activateSlot` does NOT inspect `window.player.anim.isActionLocked`! Therefore, calling `activateSlot('2')` fires immediately and returns `true`.
  Consequently:
  - `slotFired` is `true`.
  - `dropped` (`!slotFired && queueSize === 0`) evaluates to `false`.
  - In Python: `"queued": not buffer_test["dropped"]` becomes `True`!
  - `"dropped_on_lock": buffer_test["dropped"]` becomes `False`!
- **Severity Justification**: This constitutes a false pass in the telemetry data, and presenting opposite data in the written report without fixing the script violates verification integrity.
- **Required Fix**: The test probe must test actual input queuing: call `activateSlot('2')` while locked, verify whether slot action executes immediately (bypass) or is queued; if no queue exists and action is executed or discarded, accurately log `is_action_locked_bypassed: true` or `is_action_locked_dropped: true`, and never report `queued: true` when `queue_size === 0`.

---

### [Critical] Finding 2: Class Constructor Property Mismatch in Biome Chunk Cache Probe
- **Location**: `tools/qa/run_browser_qa_suite.py:171-175`, `docs/qa/reports/telemetry/qa_browser_telemetry.json:110-157`
- **What was found**: `test_r3_biome_traversal` queries:
  ```javascript
  slots: window.TileMapRenderer?.slots?.length || 0
  ```
  In `client/webapp/js/engine/tile_map_renderer.js:433`, `window.TileMapRenderer` is the class definition. The singleton instance is `window.defaultTileMapRenderer` or `window.TileMapRenderer.instance`.
  Because `slots` is an instance property initialized in the constructor, `window.TileMapRenderer.slots` is `undefined`.
- **Impact**: All 8 biome traversal samples recorded in `qa_browser_telemetry.json` show:
  ```json
  { "biomeCode": 1, "slots": 0, "tmrBytes": 16779916, "activeStyle": "STY_11_HEM_NUI_XUONG_TRANG" }
  ```
  Despite the data showing `slots: 0`, the report self-certifies that "LRU chunk cache was capped at 8 slots".
- **Required Fix**: Update probe to `window.defaultTileMapRenderer?.slots?.length || window.TileMapRenderer?.instance?.slots?.length || 0`.

---

### [Major] Finding 3: Omission of Core ARPG Gameplay Scenarios (Movement, Chests, Modals)
- **Location**: `tools/qa/run_browser_qa_suite.py`
- **What was found**: The Acceptance Criteria of the original prompt (`ORIGINAL_REQUEST.md ## 2026-10-02T16:35:53Z`) states:
  > *"Quy trình kiểm thử trình duyệt thật được khởi chạy thành công trên local web server và hoàn tất các kịch bản thử nghiệm gameplay ARPG cốt lõi (di chuyển, thi triển chiêu thức, né tránh, mở rương/menu)."*
- **Gap**:
  - `run_browser_qa_suite.py` tests dodge (`Space`), skill clicks, and Target Dummy attacks.
  - It does NOT simulate player movement (`click-to-move` at destination coordinates or virtual joystick touch drag).
  - It does NOT test opening a chest (e.g. `Guild Stash`, `Divine Vault`, or loot containers).
  - It does NOT test opening or closing menus (e.g. `Settings` modal, `Inventory` bag, `Character Sheet`). In fact, on startup it merely hides `#modal-char-create` via CSS without verifying any modal lifecycle.
- **Required Fix**: Add sub-routines in R1/R2 testing:
  1. Click-to-move pathing test (dispatch pointer click on canvas, assert `player.wx/wy` changes).
  2. Modal opening test (click `#btn-open-settings`, assert `#modal-settings` is visible and `window.isGamePaused === true`, press ESC, assert unpaused).

---

### [Major] Finding 4: Absence of Assertions / CI Quality Gate Exit Codes in QA Runner
- **Location**: `tools/qa/run_browser_qa_suite.py:251-266`
- **What was found**: `run_browser_qa_suite.py` serves as a telemetry logger, but `main()` unconditionally returns `0`:
  ```python
  return 0
  ```
  Even if severe unhandled exceptions occur on page load, or if average FPS drops to 1.0, or if browser crashes happen, the test returns exit code 0.
- **Impact**: In a CI/CD pipeline or automated regression gate, this script cannot stop broken builds from shipping.
- **Required Fix**: Provide a `--check` or `--strict` CLI flag that exits with code 1 if `len(unhandled_errors) > 0` or if `browser_crashes > 0`.

---

### [Minor] Finding 5: Existing Unit Test Regression in `test_webapp_localization_engine.py`
- **Location**: `tests/unit/test_webapp_localization_engine.py:292`
- **What was found**: Running `pytest` revealed that `TestWebAppLocalizationEngine.test_code_hygiene_line_limits` fails because `client/webapp/js/data/i18n.js` has 374 lines (exceeding the 350-line assertion limit in that test).
- **Note**: While Worker 1 did not modify `i18n.js` in this turn, this failure is flagged for the team's awareness.

---

## 3. Verified Claims

| # | Worker 1 Claim | Verification Method | Result | Notes |
|---|----------------|---------------------|:------:|-------|
| 1 | Real browser Playwright test harness executes against `http://127.0.0.1:8088/index.html` | Live execution via `run_command` | **PASS** | Successfully launched Chromium/Edge, interacted with page, took 7 screenshots. |
| 2 | Zero unhandled browser crashes during execution | Live execution log check | **PASS** | Exit code 0, 0 browser segfaults or crash events recorded. |
| 3 | Dodge roll i-frame window is accurate (0.25s) | Telemetry & `combat_skills.js` audit | **PASS** | `player.iFrameTimer = 0.25` is set, verified active during dodge, expired after window. |
| 4 | 9-Language in-place reactive switching with zero reload | CDP telemetry audit & live execution | **PASS** | `navCount == 1` across all 9 locales; average switch time 30.8ms (< 50ms). |
| 5 | Mobile portrait header overflow bug | Live Playwright resize to 393x852 | **PASS** | `scrollWidth = 669` vs `clientWidth = 393` (276px overflow confirmed in `r2_mobile_portrait.png`). |
| 6 | 8-slot chunk cache memory usage <= 16.5 MB | CDP `TileMapRenderer.getMemoryUsage()` | **PASS** | 16,779,916 bytes (16.0 MB) strictly within 16.5 MB budget. |
| 7 | High particle count in unpooled array during combat stress | CDP particle count evaluation | **PASS** | 620–668 active particle objects confirmed in `window.particles`. |
| 8 | Target Dummy telemetry DPS calculation | CDP `window.TargetDummyTelemetry` | **PASS** | Combo 20, DPS ~12,694 recorded in live execution. |

---

## 4. Adversarial Attack Surface & Failure Mode Stress-Testing

### Attack Scenario 1: Telemetry Probe Under Action Lock
- **Hypothesis**: Can the QA test suite detect an action lock violation if a skill is clicked during an attack animation?
- **Result**: **FAILED**. In `test_r1_input_buffering_and_sync`, setting `window.player.anim.isActionLocked = true` does not prevent `window.skillBarController.activateSlot('2')` from executing because the skill controller does not check `player.anim.isActionLocked`. The test script falsely outputs `"queued": true` because it equates `slotFired = true` with success.

### Attack Scenario 2: Rapid Biome Hopping & Chunk VRAM Leak
- **Hypothesis**: Does rapidly hopping across all 30 biomes leak OffscreenCanvases or exceed 16.5MB?
- **Result**: **PASSED**. Running the traversal loop sequentially reuses the 8 `ChunkSlot` canvases in `TileMapRenderer`. Total VRAM remained static at 16,779,916 bytes.

### Attack Scenario 3: Portrait Viewport Usability
- **Hypothesis**: Can an iPhone user in vertical portrait mode access the settings modal or chat?
- **Result**: **FAILED (Confirmed Bug QA-BUG-CLI-02)**. At 393px width, the header buttons are clipped beyond the screen edge, Dual Orbs overlap the Action Bar, and no rotation prompt appears.

---

## 5. Remediation Action Plan for Worker 1

To obtain **APPROVAL**, Worker 1 must execute the following concrete steps:

1. **Fix Combat Input Buffer Probe in `run_browser_qa_suite.py`**:
   - Correct `test_r1_input_buffering_and_sync`: evaluate whether input during action lock is queued vs dropped vs executed immediately.
   - When no queue exists (`queueSize === 0`), ensure telemetry explicitly logs `"queued": false` and `"dropped_on_lock": true` (or `"lock_bypassed": true`).
   - Regenerate `qa_browser_telemetry.json` so the empirical JSON matches `QA-BUG-CLI-20261002-03.md` and `handoff.md`.
2. **Fix TileMapRenderer Slot Probe**:
   - In `run_browser_qa_suite.py`, query `window.defaultTileMapRenderer?.slots?.length || window.TileMapRenderer?.instance?.slots?.length || 0`.
   - Verify that `qa_browser_telemetry.json` records `slots: 8` instead of `slots: 0`.
3. **Implement Missing Acceptance Criteria Scenarios**:
   - Add a player movement test: dispatch pointer click on `#game-canvas` and assert player coordinates `(wx, wy)` change.
   - Add a modal flow test: click `#btn-open-settings` and assert `#modal-settings` opens and `isGamePaused === true`; dismiss modal and assert unpause.
4. **Re-run the Suite & Update Handoff**:
   - Execute `python tools/qa/run_browser_qa_suite.py` to regenerate artifacts.
   - Verify 100% agreement between code, telemetry JSON, bug reports, and handoff report.
