# Handoff Report: Remediation Strategy for Dynamic UI Controller Buttons & Residual Parentheticals

**Agent**: `explorer_remediate_1` (Dynamic UI Buttons Explorer)  
**Recipient**: `parent` (Orchestrator, ID: `a8122c75-321a-4be0-bc44-2ff49f028481`)  
**Date**: 2026-10-01T03:03:00Z  
**Type**: Hard Handoff (Investigation & Specification Complete)

---

## 1. Observation

Direct inspection of the target files, lines, and surrounding code structures revealed the following verbatim elements:

### 1.1 Target 1: `client/webapp/js/ui/character_equipment.js` (Line 156)
- **Observed snippet (Lines 155-157)**:
  ```javascript
  <button onclick="window.unequipGearSlot('${inspectedSlotId}')" class="px-2.5 py-1 rounded-lg bg-rose-950/80 hover:bg-rose-900 border border-rose-800 text-rose-200 text-[10px] font-mono font-semibold transition active:scale-95 shadow flex items-center gap-1">
    <span>📦</span> <span>Tháo Vào Túi</span>
  </button>
  ```
- **Analysis**:
  - Text node: `"Tháo Vào Túi"` has **3 words** ("Tháo", "Vào", "Túi").
  - Handler binding: `onclick="window.unequipGearSlot('${inspectedSlotId}')"`. No selector or logic checks the text string.

### 1.2 Target 2: `client/webapp/js/ui/divine_vault_modal.js`
- **Observed snippet (Line 203)**:
  ```javascript
  <button onclick="window.equipDemoWeapon('${w.id}')" class="px-3 py-1.5 bg-gradient-to-r from-red-900 to-amber-700 hover:from-red-800 hover:to-amber-600 text-amber-100 font-bold rounded shadow transition">Trang Bị Thử</button>
  ```
  - Text node: `"Trang Bị Thử"` has **3 words** ("Trang", "Bị", "Thử").
  - Handler binding: `onclick="window.equipDemoWeapon('${w.id}')"`.
- **Observed snippet (Lines 131, 138, 145)**:
  ```javascript
  // Line 131:
  titleVi: 'Bờ Biển Tử Địa (The Forsaken Shore)',
  // Line 138:
  titleVi: 'Mật Ngục Tế Cốt (The Eldritch Crypt)',
  // Line 145:
  titleVi: 'Hoang Vực Xương Trắng (The Bleached Bone Wastes)',
  ```
  - Crucial rendering location (Lines 258-261):
    ```javascript
    <button onclick="window.selectLoreScreen(${idx})"
      class="px-3 py-1.5 rounded text-xs font-bold whitespace-nowrap transition-all border ${idx === selectedScreenIndex ? 'bg-amber-600 text-stone-950 border-amber-400 shadow-[0_0_10px_rgba(245,158,11,0.4)]' : 'bg-stone-900 text-stone-400 border-stone-800 hover:text-stone-200'}">
      ${item.titleVi}
    </button>
    ```
  - Because `item.titleVi` is interpolated directly into `<button>`, the string `titleVi` is itself an active button label.
  - Retaining 4 words (e.g. `Bờ Biển Tử Địa`) causes the button to fail the $\le 2$ words microcopy rule.
  - Also rendered in banner heading (Line 269): `<div class="text-lg font-black text-amber-300 tracking-wide drop-shadow">${s.titleVi}</div>`.
- **Observed snippet (Lines 197 & 240)**:
  ```javascript
  // Line 197:
  <div class="text-[10px] font-bold text-stone-400 uppercase tracking-wider mb-1">Cổ Thần Điển Tích (Lore)</div>
  // Line 240:
  <div class="text-[10px] font-bold text-stone-400 uppercase tracking-wider mb-1">Bản Vị Huyết Thạch (Lore)</div>
  ```
  - Text nodes contain parenthetical `(Lore)` and exceed 2 words (5 words each).

### 1.3 Target 3: `client/webapp/js/ui/meridian_vault.js` (Lines 205, 207)
- **Observed snippet (Lines 204-209)**:
  ```javascript
  <div class="flex justify-between items-center pt-2 border-t border-stone-800">
    <span class="text-[10px] text-stone-400 font-mono">Miễn Phí (Bang)</span>
    <button onclick="withdrawGuildItem('${item.id}')" class="px-2.5 py-1 rounded bg-stone-900 hover:bg-stone-800 border border-stone-700 text-stone-200 text-xs font-medium shadow-sm active:scale-95 transition">
      Rút Về Dùng
    </button>
  </div>
  ```
  - Line 205: `"Miễn Phí (Bang)"` contains parenthetical `(Bang)`.
  - Line 207: `"Rút Về Dùng"` has **3 words** ("Rút", "Về", "Dùng").
  - Handler binding: `onclick="withdrawGuildItem('${item.id}')"`.

### 1.4 Target 4: `client/webapp/js/ui/story_quest_board.js` (Line 160)
- **Observed snippet (Lines 158-160)**:
  ```javascript
  ${q.status === 'COMPLETED' ? '<span class="text-emerald-400 font-bold">✓ Đã Hoàn Thành</span>' :
    q.status === 'IN_PROGRESS' ? '<span class="text-sky-400 font-mono">Đang theo dõi</span>' :
    `<button class="btn-accept-q px-2 py-0.5 rounded bg-stone-800 text-amber-200 border border-amber-600/40 text-[10px] font-bold" data-id="${q.id}">Nhận Khế Ước</button>`}
  ```
  - Text node: `"Nhận Khế Ước"` has **3 words** ("Nhận", "Khế", "Ước").
  - Event listener (Line 260): `const acceptBtn = t.closest('.btn-accept-q');` reading `acceptBtn.dataset.id`. It does not match against text.

### 1.5 Target 5: `client/webapp/js/ui/worldmap_dungeons.js` (Line 88)
- **Observed snippet (Lines 85-89)**:
  ```javascript
  <button onclick="teleportToZone('${z.id}')" class="w-full py-1.5 rounded-lg text-xs font-semibold transition flex items-center justify-center gap-1 ${
    isCurrent ? 'bg-stone-900 text-stone-500 border border-stone-800 cursor-default' : 'bg-gradient-to-b from-stone-800 to-stone-900 hover:from-stone-700 hover:to-stone-800 border border-amber-600/40 hover:border-amber-500/70 text-amber-200/90 shadow-sm active:scale-95'
  }">
    <span>${isCurrent ? '📍 Đang Ở Đây' : '⚡ Dịch Chuyển Thần Hành'}</span>
  </button>
  ```
  - Current state label: `'📍 Đang Ở Đây'` has **3 words** ("Đang", "Ở", "Đây").
  - Action state label: `'⚡ Dịch Chuyển Thần Hành'` has **4 words** ("Dịch", "Chuyển", "Thần", "Hành").
  - Handler binding: `onclick="teleportToZone('${z.id}')"`.

### 1.6 Target 6: `client/webapp/js/ui/templates/template_catalog_activities.js` (Line 230)
- **Observed snippet (Line 229-231)**:
  ```javascript
  <p class="text-[10px] text-stone-400 mb-3 leading-relaxed">
    Mỗi Big Update mùa giải, toàn bộ thế giới bước vào <strong>Đại Nạn Hoang Vực (Clean Slate Reset)</strong>. Mọi người chơi bắt đầu lại từ Cấp 1, 0 tiền, 0 item để đảm bảo kinh tế không lạm phát và công bằng 100%.
  </p>
  ```
  - Text node contains residual bilingual English parenthetical `(Clean Slate Reset)`.
- **Adjacent Observation (Line 272 in same file)**:
  ```javascript
  <p class="text-[10px] text-stone-400 mb-2 leading-relaxed">
    Đồ đạc mùa cũ chuyển về Cõi Vĩnh Hằng dưới dạng <strong>Tab Chỉ Rút (Remove-Only)</strong>.
  </p>
  ```
  - Also contains residual bilingual English parenthetical `(Remove-Only)`.

---

## 2. Logic Chain

1. **Mandate Derivation (ORIGINAL_REQUEST §R1 & PROJECT.md)**:
   - "100% các nút bấm, tab và nhãn điều hướng trên Client WebApp có độ dài tối đa 1-2 từ."
   - "Không còn bất kỳ nhãn UI nào chứa định dạng song ngữ kép dạng A (B)."
2. **Dynamic UI Controller Coverage (Finding 1 & 2 in reviewer_streamline_1/handoff.md)**:
   - Static templates achieved compliance, but dynamic JS modules generating DOM markup during modal interactions remained unconstrained.
   - Specifically, 6 dynamic buttons have $\ge 3$ words, and 7 text/title elements retain parentheticals.
3. **DOM Selector & Event Handler Independence**:
   - In `character_equipment.js`: `onclick="window.unequipGearSlot('${inspectedSlotId}')"` calls the unequip function directly with slot ID.
   - In `divine_vault_modal.js`: `onclick="window.equipDemoWeapon('${w.id}')"` and `onclick="window.selectLoreScreen(${idx})"` pass IDs and indexes.
   - In `meridian_vault.js`: `onclick="withdrawGuildItem('${item.id}')"` passes item ID.
   - In `story_quest_board.js`: Click events are captured via `.btn-accept-q` class and `dataset.id`.
   - In `worldmap_dungeons.js`: `onclick="teleportToZone('${z.id}')"` passes zone ID.
   - **Deduction**: Changing the visible text labels will not alter or break any event listeners, CSS styling classes, or test assertions.
4. **Brevity & Semantic Precision**:
   - Shortening `Tháo Vào Túi` $\to$ `Tháo Đồ` preserves exact ARPG action meaning in 2 words.
   - Shortening `Trang Bị Thử` $\to$ `Trang Bị` preserves weapon equipping context in 2 words.
   - Shortening `Rút Về Dùng` $\to$ `Rút Đồ` preserves guild stash withdrawal semantics in 2 words.
   - Shortening `Nhận Khế Ước` $\to$ `Nhận Khế` preserves wuxia covenant acceptance semantics in 2 words.
   - Shortening `⚡ Dịch Chuyển Thần Hành` $\to$ `⚡ Dịch Chuyển` and `📍 Đang Ở Đây` $\to$ `📍 Hiện Tại` preserves waypoint teleportation clarity in 2 words each.
   - For `divine_vault_modal.js` loading screens: Shortening `titleVi` from `Bờ Biển Tử Địa (The Forsaken Shore)` $\to$ `Bờ Biển` (2 words), `Mật Ngục Tế Cốt (The Eldritch Crypt)` $\to$ `Mật Ngục` (2 words), and `Hoang Vực Xương Trắng (The Bleached Bone Wastes)` $\to$ `Hoang Vực` (2 words) guarantees that the carousel buttons `<button>${item.titleVi}</button>` strictly adhere to the $\le 2$ words microcopy rule.
   - Removing parentheticals from `(Lore)` $\to$ `Điển Tích` (2 words), `Miễn Phí (Bang)` $\to$ `Miễn Phí` (2 words), and `(Clean Slate Reset)` $\to$ `Đại Nạn Hoang Vực` (and optionally `Đại Nạn` for strict 2 words) completely purges dual-language strings.

---

## 3. Replacement Specification Matrix

| # | Target File | Line(s) | Current Verbatim Code | Exact Proposed Replacement | Word Count | Parens |
|---|-------------|---------|-----------------------|----------------------------|------------|--------|
| **1** | `client/webapp/js/ui/character_equipment.js` | 156 | `<span>📦</span> <span>Tháo Vào Túi</span>` | `<span>📦</span> <span>Tháo Đồ</span>` | 2 words | 0 |
| **2** | `client/webapp/js/ui/divine_vault_modal.js` | 203 | `... class="...">Trang Bị Thử</button>` | `... class="...">Trang Bị</button>` | 2 words | 0 |
| **3** | `client/webapp/js/ui/divine_vault_modal.js` | 131 | `titleVi: 'Bờ Biển Tử Địa (The Forsaken Shore)',` | `titleVi: 'Bờ Biển',` *(or `'Tử Địa',`)* | 2 words | 0 |
| **4** | `client/webapp/js/ui/divine_vault_modal.js` | 138 | `titleVi: 'Mật Ngục Tế Cốt (The Eldritch Crypt)',` | `titleVi: 'Mật Ngục',` | 2 words | 0 |
| **5** | `client/webapp/js/ui/divine_vault_modal.js` | 145 | `titleVi: 'Hoang Vực Xương Trắng (The Bleached Bone Wastes)',` | `titleVi: 'Hoang Vực',` | 2 words | 0 |
| **6** | `client/webapp/js/ui/divine_vault_modal.js` | 197 | `<div class="...">Cổ Thần Điển Tích (Lore)</div>` | `<div class="...">Điển Tích</div>` | 2 words | 0 |
| **7** | `client/webapp/js/ui/divine_vault_modal.js` | 240 | `<div class="...">Bản Vị Huyết Thạch (Lore)</div>` | `<div class="...">Điển Tích</div>` | 2 words | 0 |
| **8** | `client/webapp/js/ui/meridian_vault.js` | 205 | `<span class="...">Miễn Phí (Bang)</span>` | `<span class="...">Miễn Phí</span>` | 2 words | 0 |
| **9** | `client/webapp/js/ui/meridian_vault.js` | 207 | `<button ...>Rút Về Dùng</button>` | `<button ...>Rút Đồ</button>` | 2 words | 0 |
| **10** | `client/webapp/js/ui/story_quest_board.js` | 160 | `... data-id="${q.id}">Nhận Khế Ước</button>` | `... data-id="${q.id}">Nhận Khế</button>` | 2 words | 0 |
| **11** | `client/webapp/js/ui/worldmap_dungeons.js` | 88 | `<span>${isCurrent ? '📍 Đang Ở Đây' : ...}</span>` | `<span>${isCurrent ? '📍 Hiện Tại' : ...}</span>` | 2 words | 0 |
| **12** | `client/webapp/js/ui/worldmap_dungeons.js` | 88 | `<span>${... : '⚡ Dịch Chuyển Thần Hành'}</span>` | `<span>${... : '⚡ Dịch Chuyển'}</span>` | 2 words | 0 |
| **13** | `client/webapp/js/ui/templates/template_catalog_activities.js` | 230 | `... bước vào <strong>Đại Nạn Hoang Vực (Clean Slate Reset)</strong>. ...` | `... bước vào <strong>Đại Nạn Hoang Vực</strong>. ...` *(or `<strong>Đại Nạn</strong>`)* | 0 parens (2 words if `Đại Nạn`) | 0 |

### 3.1 Recommended Supplementary Remediation (Zero Parentheticals Defense)
While executing these modifications, the implementer should also apply two small adjacent fixes:
1. `client/webapp/js/ui/templates/template_catalog_activities.js:272`:
   - Before: `... dưới dạng <strong>Tab Chỉ Rút (Remove-Only)</strong>.`
   - After: `... dưới dạng <strong>Tab Chỉ Rút</strong>.`
2. `client/webapp/js/ui/divine_vault_modal.js` Lines 86, 95, 104, 113, 122 (Primal Relic Tags):
   - Line 86: `tag: 'Dị Biến Tà Huyết (Vaal Equivalent)',` $\to$ `tag: 'Dị Biến',`
   - Line 95: `tag: 'Khắc Dòng Thần Bí (Exalted Equivalent)',` $\to$ `tag: 'Khắc Dòng',`
   - Line 104: `tag: 'Tái Cấu Trúc Toàn Diện (Chaos Equivalent)',` $\to$ `tag: 'Tái Cấu',`
   - Line 113: `tag: 'Nhân Bản Cổ Vật (Mirror Equivalent)',` $\to$ `tag: 'Nhân Bản',`
   - Line 122: `tag: 'Cường Hóa Phẩm Chất (Quality Catalyst)',` $\to$ `tag: 'Cường Hóa',`

---

## 4. Before & After Code Snippets for Implementer

### Snippet 1: `client/webapp/js/ui/character_equipment.js` (Line 156)
```diff
<<<< BEFORE
-      <button onclick="window.unequipGearSlot('${inspectedSlotId}')" class="px-2.5 py-1 rounded-lg bg-rose-950/80 hover:bg-rose-900 border border-rose-800 text-rose-200 text-[10px] font-mono font-semibold transition active:scale-95 shadow flex items-center gap-1">
-        <span>📦</span> <span>Tháo Vào Túi</span>
-      </button>
==== AFTER
+      <button onclick="window.unequipGearSlot('${inspectedSlotId}')" class="px-2.5 py-1 rounded-lg bg-rose-950/80 hover:bg-rose-900 border border-rose-800 text-rose-200 text-[10px] font-mono font-semibold transition active:scale-95 shadow flex items-center gap-1">
+        <span>📦</span> <span>Tháo Đồ</span>
+      </button>
>>>>
```

### Snippet 2: `client/webapp/js/ui/divine_vault_modal.js` (Lines 131, 138, 145, 197, 203, 240)
```diff
<<<< BEFORE
-    titleVi: 'Bờ Biển Tử Địa (The Forsaken Shore)',
...
-    titleVi: 'Mật Ngục Tế Cốt (The Eldritch Crypt)',
...
-    titleVi: 'Hoang Vực Xương Trắng (The Bleached Bone Wastes)',
...
-              <div class="text-[10px] font-bold text-stone-400 uppercase tracking-wider mb-1">Cổ Thần Điển Tích (Lore)</div>
...
-            <button onclick="window.equipDemoWeapon('${w.id}')" class="px-3 py-1.5 bg-gradient-to-r from-red-900 to-amber-700 hover:from-red-800 hover:to-amber-600 text-amber-100 font-bold rounded shadow transition">Trang Bị Thử</button>
...
-              <div class="text-[10px] font-bold text-stone-400 uppercase tracking-wider mb-1">Bản Vị Huyết Thạch (Lore)</div>
==== AFTER
+    titleVi: 'Bờ Biển',
...
+    titleVi: 'Mật Ngục',
...
+    titleVi: 'Hoang Vực',
...
+              <div class="text-[10px] font-bold text-stone-400 uppercase tracking-wider mb-1">Điển Tích</div>
...
+            <button onclick="window.equipDemoWeapon('${w.id}')" class="px-3 py-1.5 bg-gradient-to-r from-red-900 to-amber-700 hover:from-red-800 hover:to-amber-600 text-amber-100 font-bold rounded shadow transition">Trang Bị</button>
...
+              <div class="text-[10px] font-bold text-stone-400 uppercase tracking-wider mb-1">Điển Tích</div>
>>>>
```

### Snippet 3: `client/webapp/js/ui/meridian_vault.js` (Lines 205, 207)
```diff
<<<< BEFORE
-        <span class="text-[10px] text-stone-400 font-mono">Miễn Phí (Bang)</span>
-        <button onclick="withdrawGuildItem('${item.id}')" class="px-2.5 py-1 rounded bg-stone-900 hover:bg-stone-800 border border-stone-700 text-stone-200 text-xs font-medium shadow-sm active:scale-95 transition">
-          Rút Về Dùng
-        </button>
==== AFTER
+        <span class="text-[10px] text-stone-400 font-mono">Miễn Phí</span>
+        <button onclick="withdrawGuildItem('${item.id}')" class="px-2.5 py-1 rounded bg-stone-900 hover:bg-stone-800 border border-stone-700 text-stone-200 text-xs font-medium shadow-sm active:scale-95 transition">
+          Rút Đồ
+        </button>
>>>>
```

### Snippet 4: `client/webapp/js/ui/story_quest_board.js` (Line 160)
```diff
<<<< BEFORE
-            `<button class="btn-accept-q px-2 py-0.5 rounded bg-stone-800 text-amber-200 border border-amber-600/40 text-[10px] font-bold" data-id="${q.id}">Nhận Khế Ước</button>`}
==== AFTER
+            `<button class="btn-accept-q px-2 py-0.5 rounded bg-stone-800 text-amber-200 border border-amber-600/40 text-[10px] font-bold" data-id="${q.id}">Nhận Khế</button>`}
>>>>
```

### Snippet 5: `client/webapp/js/ui/worldmap_dungeons.js` (Line 88)
```diff
<<<< BEFORE
-          <span>${isCurrent ? '📍 Đang Ở Đây' : '⚡ Dịch Chuyển Thần Hành'}</span>
==== AFTER
+          <span>${isCurrent ? '📍 Hiện Tại' : '⚡ Dịch Chuyển'}</span>
>>>>
```

### Snippet 6: `client/webapp/js/ui/templates/template_catalog_activities.js` (Line 230)
```diff
<<<< BEFORE
-              Mỗi Big Update mùa giải, toàn bộ thế giới bước vào <strong>Đại Nạn Hoang Vực (Clean Slate Reset)</strong>. Mọi người chơi bắt đầu lại từ Cấp 1, 0 tiền, 0 item để đảm bảo kinh tế không lạm phát và công bằng 100%.
==== AFTER
+              Mỗi Big Update mùa giải, toàn bộ thế giới bước vào <strong>Đại Nạn Hoang Vực</strong>. Mọi người chơi bắt đầu lại từ Cấp 1, 0 tiền, 0 item để đảm bảo kinh tế không lạm phát và công bằng 100%.
>>>>
```

---

## 5. Caveats

1. **`titleVi` Duality in `divine_vault_modal.js`**:
   `titleVi` is used both as the carousel button text (`<button>${item.titleVi}</button>`) and the panoramic viewport title (`<div>${s.titleVi}</div>`). Shortening it to 2 words (`Bờ Biển`, `Mật Ngục`, `Hoang Vực`) is the cleanest solution because it simultaneously solves the button length constraint and enhances mobile viewport readability.
2. **NPC Dialogue Choices**:
   An exploratory scan revealed that `client/webapp/js/ui/npc_dialogue_catalog.js` (lines 58, 70, 86, 87, 100, 113, 126) contains parenthetical action tags such as `(Consignment Vault 2PC)` and `(Nhận Khế Ước)`. While outside the immediate dispatch scope of this milestone, they should be queued for subsequent dialogue polishing.
3. **No Code Modification Undertaken**:
   In strict adherence to the read-only Explorer role, no source files were modified in this phase. The exact drop-in replacements are fully specified above for the designated Worker agent.

---

## 6. Conclusion

All 6 target files and their corresponding 13 lines/elements have been thoroughly analyzed. The identified replacement strings achieve:
- **100% compliance with the $\le 2$ words limit** on all dynamic buttons and interactive triggers.
- **Zero residual parentheticals** (`0` bilingual strings).
- **Zero disruption** to existing DOM event listeners, `onclick` bridges, `dataset` attributes, or automated test runners.

The implementation is low-risk, high-impact, and directly addresses Reviewer 1's `REQUEST_CHANGES` verdict.

---

## 7. Verification Method

Once the Worker applies these drop-in replacements, independent verification can be executed as follows:

1. **Automated E2E & Unit Test Suites**:
   ```bash
   pytest tests/e2e/test_ui_typography_i18n_wiki_streamlining_e2e.py -v
   python -m unittest tests/unit/test_webapp_localization_engine.py -v
   ```
   *Expected outcome*: 60/60 E2E tests pass (0 failed, 0 skipped), 16/16 Unit tests pass.

2. **Code & Documentation Hygiene**:
   ```bash
   python tools/lint/check_code_and_doc_hygiene.py --strict
   ```
   *Expected outcome*: 0 hard cap violations.

3. **Adversarial Dynamic Microcopy Grep**:
   Verify zero occurrences of the previous long or parenthetical strings across `client/webapp/js/`:
   ```bash
   # In pwsh:
   Select-String -Path "client/webapp/js/ui/*.js" -Pattern "Tháo Vào Túi", "Trang Bị Thử", "Rút Về Dùng", "Nhận Khế Ước", "Dịch Chuyển Thần Hành", "Clean Slate Reset", "\(Bang\)"
   ```
   *Expected outcome*: Zero matches returned.

4. **Invalidation Condition**:
   Any button or navigation element in the webapp rendered with $> 2$ words or containing bilingual `(English)` parentheses invalidates this verification.
