# Handoff Report: Auxiliary UI Modules Scan (Button Microcopy & Parenthetical Audit)

**Agent**: explorer_remediate_3  
**Role**: Auxiliary UI Modules Scanner  
**Target Scope**: UI scripts in `client/webapp/js/ui/` and related modal templates in `client/webapp/templates/`  
**Date**: 2026-10-01T03:05:00Z  

---

## 1. Observation

A full scan of `client/webapp/js/ui/` and `client/webapp/templates/` was conducted to audit button microcopy against the requirements in `ORIGINAL_REQUEST.md` (§R1):
> *"100% nhãn UI phải là thuật ngữ ngắn gọn từ 1 đến 2 từ (ví dụ: 'Động Thiên', 'Bản Đồ', 'Tàn Đồ', 'Võ Học', 'Toàn Màn'). Loại bỏ hoàn toàn định dạng nhãn song ngữ kép cồng kềnh Tiếng Việt (English) trên các nút bấm... tuyệt đối không để nội dung nút bấm hay nhãn UI dài 3-4 từ."*

### 1.1. Verified Clean Modules (Zero Button Violations)
1. **`client/webapp/js/ui/chat_ui.js`**:
   - Lines 7-14 (`CHANNELS`): All labels are strictly 2 words: `"Thế Giới"`, `"Khu Vực"`, `"Bang Hội"`, `"Đội Ngũ"`, `"Mật Thư"`, `"Hệ Thống"`, `"Chiêu Mộ"`, `"Góp Ý"`.
   - Lines 18-26 (`CHANNEL_I18N`): All 9 language dictionaries use 1-2 words (e.g., `World`, `Zone`, `Guild`, `世界`, `ワールド`, etc.).
   - Line 71: Inline item button `[${name}]` renders item name.
   - Line 123, 300: References `#chat-send-btn` whose label is `"Gửi"` (1 word) in `index.html:160` and `template_catalog_system.js:454`.
2. **`client/webapp/js/ui/hud_orbs.js`**:
   - Pure HTML5 Canvas 2D liquid dynamics engine and telemetry numbers (`displayedHp`, `displayedMana`). Zero button creation or text microcopy.
3. **`client/webapp/js/ui/skill_bar_controller.js`**:
   - Manages radial cooldown sweeps, hotkeys, and charges. Zero button creation.
4. **`client/webapp/js/ui/shop_megashop.js`**:
   - All runtime generated buttons in `renderMegaShop()` are strictly 1-2 words without parentheticals:
     - Line 82: `<span>🛒</span> Nạp Gói` (2 words)
     - Line 102: `<span>✨</span> Mở Rương` (2 words)
     - Line 118: `<span>🛍️</span> Mua` (1 word)
5. **`client/webapp/js/ui/char_creation.js`**:
   - Line 92: Character selection button renders `"Vào Game"` (2 words).
6. **`client/webapp/js/ui/feedback.js`**:
   - Zero dynamic button creation with length violations.

---

### 1.2. Identified Violations in JavaScript UI Modules

#### Violation A: `client/webapp/js/ui/inventory_stash.js`
- **Location**: Lines 18-20 (`stashTabs`) & Lines 147-153 (`renderStashTab`)
- **Observed Code**:
  ```javascript
  18: export const stashTabs = {
  19:   tab_general: { name: 'Kho Chung', slots: {} },
  20:   tab_currency: { name: 'Đá Huyết & Tiền Tệ', slots: {} },
  21:   tab_equipment: { name: 'Binh Khí & Thần Cốt', slots: {} }
  22: };
  ...
  147: const b = document.createElement('button');
  151: b.innerText = t.name;
  153: tabSelector.appendChild(b);
  ```
- **Direct Observation**:
  - Button text `tab_currency.name`: `"Đá Huyết & Tiền Tệ"` contains 5 tokens (exceeds 2 words).
  - Button text `tab_equipment.name`: `"Binh Khí & Thần Cốt"` contains 5 tokens (exceeds 2 words).

#### Violation B: `client/webapp/js/ui/divine_vault_modal.js`
- **Location 1**: Line 203 (`renderModalContent` under `currentTab === 'weapons'`)
- **Observed Code**:
  ```html
  203: <button onclick="window.equipDemoWeapon('${w.id}')" class="px-3 py-1.5 ...">Trang Bị Thử</button>
  ```
- **Direct Observation**: `"Trang Bị Thử"` contains 3 words (exceeds 2 words).
- **Location 2**: Lines 258-261 (`renderModalContent` under `currentTab === 'screens'`)
- **Observed Code**:
  ```javascript
  257: ${LORE_SCREENS.map((item, idx) => `
  258:   <button onclick="window.selectLoreScreen(${idx})"
  259:     class="px-3 py-1.5 rounded text-xs font-bold whitespace-nowrap transition-all border ...">
  260:     ${item.titleVi}
  261:   </button>
  262: `).join('')}
  ```
  Where `LORE_SCREENS` (lines 128-150) defines:
  - 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)'`
- **Direct Observation**:
  - The carousel buttons render `item.titleVi` directly, containing 7 to 9 words and bilingual parentheticals `(English)`.

#### Violation C: `client/webapp/js/ui/meridian_vault.js`
- **Location**: Lines 206-208 (`renderGuildStash`)
- **Observed Code**:
  ```html
  206: <button onclick="withdrawGuildItem('${item.id}')" class="px-2.5 py-1 rounded ...">
  207:   Rút Về Dùng
  208: </button>
  ```
- **Direct Observation**: `"Rút Về Dùng"` contains 3 words (exceeds 2 words).

#### Violation D: `client/webapp/js/ui/character_equipment.js`
- **Location**: Lines 155-157
- **Observed Code**:
  ```html
  155: <button onclick="window.unequipGearSlot('${inspectedSlotId}')" class="px-2.5 py-1 rounded-lg ...">
  156:   <span>📦</span> <span>Tháo Vào Túi</span>
  157: </button>
  ```
- **Direct Observation**: `"Tháo Vào Túi"` contains 3 words (exceeds 2 words).

#### Violation E: `client/webapp/js/ui/seasonal_reset.js`
- **Location**: Lines 24-27 (`seasonStashTabs`) & Lines 107-118 (`renderSeasonStash`)
- **Observed Code**:
  ```javascript
  24: export let seasonStashTabs = [
  25:   { id: 'ro_tab_01', name: '[Chỉ Rút - Mùa 1] Kho Chung', isRemoveOnly: true, items: [] },
  26:   { id: 'std_tab_01', name: 'Kho Standard Chuẩn', isRemoveOnly: false, items: [] }
  27: ];
  ...
  107: const btn = document.createElement('button');
  113: btn.innerHTML = `${tab.isRemoveOnly ? '🔒 <span class="text-amber-200">[CHỈ RÚT]</span>' : '📁'} ${tab.name} (${tab.items.length})`;
  ```
- **Direct Observation**:
  - Tab button labels evaluate to:
    - `🔒 [CHỈ RÚT] [Chỉ Rút - Mùa 1] Kho Chung (0)` (contains brackets, parentheses, 8+ words)
    - `📁 Kho Standard Chuẩn (0)` (contains 3 words + parentheses)

#### Violation F: `client/webapp/js/ui/story_quest_board.js`
- **Location**: Line 160 (`renderQuests`)
- **Observed Code**:
  ```html
  160: `<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>`
  ```
- **Direct Observation**: `"Nhận Khế Ước"` contains 3 words (exceeds 2 words).

#### Violation G: `client/webapp/js/ui/worldmap_dungeons.js`
- **Location**: Lines 85-89 (`renderDungeons`)
- **Observed Code**:
  ```javascript
  85: <button onclick="teleportToZone('${z.id}')" class="w-full py-1.5 ...">
  88:   <span>${isCurrent ? '📍 Đang Ở Đây' : '⚡ Dịch Chuyển Thần Hành'}</span>
  89: </button>
  ```
- **Direct Observation**:
  - `'📍 Đang Ở Đây'` contains 3 words.
  - `'⚡ Dịch Chuyển Thần Hành'` contains 4 words.

#### Violation H: `client/webapp/js/ui/npc_dialogue_catalog.js` (Rendered by `dialogue_npc.js:95-106`)
- **Location**: Lines 58, 70, 86, 87, 100, 113, 126
- **Observed Code**:
  ```javascript
  58: { text: 'Đưa đao đây! Lũ súc sinh đó đang ở đâu? (Nhận Khế Ước)', target: 'node_doc_co_quest_offer', action: 'accept_quest_doc_co' }
  70: { text: 'Chờ xem ta xé xác chúng! (Rời đi)', terminal: true }
  86: { text: 'Mở Rương Hắc Thị (Consignment Vault 2PC)', action: 'open_vault', terminal: true }
  87: { text: 'Mở Chợ Đen Hoang Vực (Megashop Barter)', action: 'open_megashop', terminal: true }
  100: { text: 'Khảm Cổ Cốt Ấn và đúc U Minh Cốt Đinh vào giáp (Lò Rèn)', action: 'open_forge', terminal: true }
  113: { text: 'Mở Huyết Cốt Ma Đồ (Flesh & Bone Matrix)', action: 'open_meridian', terminal: true }
  126: { text: 'Cầm lấy hũ Hỗn Nguyên Tửu này! (Giao Nộp Vật Phẩm)', target: 'node_hermit_wine_accepted', action: 'deliver_wine' }
  ```
- **Direct Observation**:
  - While `i18n_catalog.js` overrides these when I18N is initialized, the fallback strings in `npc_dialogue_catalog.js` (rendered as buttons in `dialogue_npc.js:95-106`) contain parenthetical suffixes `(...)` and bilingual annotations `(Consignment Vault 2PC)`, `(Megashop Barter)`, `(Flesh & Bone Matrix)`.

---

### 1.3. Discrepancy between Legacy Static HTML Templates vs Template Catalogs
FreeExile has two sets of HTML templates:
1. **Modern Template Catalogs** (`client/webapp/js/ui/templates/template_catalog_*.js`): Registered via `UITemplateManagerClass`. M1 has already trimmed almost all buttons here to 1-2 words.
2. **Legacy Static HTML Templates** (`client/webapp/templates/*.html`): Still retain the old multi-word and bilingual parenthetical buttons:
   - `client/webapp/templates/forge_modal.html`:
     - Line 54: `Phân Giải Trang Bị Rác (+8 Bụi)` (8 words + parenthetical)
     - Line 87: `Đập Tà Huyết Hủ Hóa (Thử Vận May)` (9 words + parenthetical)
   - `client/webapp/templates/vault_modal.html`:
     - Line 9: `🏛️ Kỳ Trân Các` (3 words)
     - Line 10: `🛡️ Rương Bang Hội` (3 words)
     - Line 11: `📜 Chỉ Số Tu Vi` (4 words)
   - `client/webapp/templates/megashop_modal.html`:
     - Line 46: `🪙 Huyết Cổ Tệ` (3 words)
     - Line 49: `⚔️ Tàn Binh & Giáp` (4 words)
     - Line 52: `📦 Cổ Man Cốt Hạp` (4 words)
     - Line 55: `🎒 Túi Sinh Tồn` (3 words)
   - `client/webapp/templates/divine_vault_modal.html`:
     - Line 19: `Cổ Cốt Huyết Thạch` (4 words)
     - Line 20: `Màn Hình Chờ & Bối Cảnh` (6 words)

---

## 2. Logic Chain

1. **Step 1 (Mandate)**: `ORIGINAL_REQUEST.md` (§R1) explicitly requires:
   - 100% of UI buttons, tabs, and navigation controls must have a maximum length of 1-2 words.
   - Elimination of bilingual dual strings `A (B)` or parenthetical text on buttons.
2. **Step 2 (Trace Execution)**:
   - While static buttons in `client/webapp/index.html` and `template_catalog_*.js` were addressed during M1, several dynamic render functions in UI controller scripts generate HTML strings containing `<button>` elements at runtime.
   - In `inventory_stash.js`, `stashTabs` defines tab names that are set to `b.innerText` on buttons. Names like `"Đá Huyết & Tiền Tệ"` (5 words) violate the length limit.
   - In `divine_vault_modal.js`, the demo weapon button is hardcoded to `"Trang Bị Thử"` (3 words). Furthermore, the loading screen selector button maps `${item.titleVi}`, which contains full lore titles with English parentheticals like `'Bờ Biển Tử Địa (The Forsaken Shore)'`.
   - In `meridian_vault.js`, `character_equipment.js`, `story_quest_board.js`, and `worldmap_dungeons.js`, interactive buttons contain `"Rút Về Dùng"` (3 words), `"Tháo Vào Túi"` (3 words), `"Nhận Khế Ước"` (3 words), `"Đang Ở Đây"` (3 words), and `"Dịch Chuyển Thần Hành"` (4 words).
   - In `seasonal_reset.js`, tab buttons dynamically concatenate `tab.name` with `(${tab.items.length})` and `[CHỈ RÚT]`, creating 8+ word button labels with brackets and parentheses.
   - In `npc_dialogue_catalog.js`, fallback dialogue choices rendered as buttons contain bilingual annotations like `(Consignment Vault 2PC)` and `(Megashop Barter)`.
   - In `client/webapp/templates/*.html`, legacy static templates still contain multi-word and parenthetical buttons, diverging from `template_catalog_*.js`.
3. **Step 3 (Conclusion)**:
   - Therefore, to achieve 100% compliance with §R1, remediations are required across these 8 JavaScript UI files and the 4 legacy static template files.

---

## 3. Caveats

1. **Read-Only Inspection**: In accordance with the Explorer archetype role constraints, this agent did not modify any source code files. All proposed changes are documented as concrete code replacements below.
2. **Legacy Template Role**: The application primarily loads modals dynamically via `template_manager.js` and `template_catalog_*.js`. However, `client/webapp/templates/*.html` are retained in the codebase and could cause confusion or test failures if an opaque test runner inspects the filesystem directly. Both sets of files should be kept in sync.
3. **Dialogue Choice Length**: Dialogue choices in `npc_dialogue_catalog.js` represent conversational options. While `i18n_catalog.js` condensed these to 1 concise sentence per §R1, removing the parenthetical suffixes `(...)` from the default strings in `npc_dialogue_catalog.js` guarantees that fallback rendering also complies with §R1.

---

## 4. Conclusion & Proposed Remediation

### 4.1. Concrete Remediation Proposals

#### 1. `client/webapp/js/ui/inventory_stash.js`
Replace lines 18-21:
```javascript
// BEFORE:
export const stashTabs = {
  tab_general: { name: 'Kho Chung', slots: {} },
  tab_currency: { name: 'Đá Huyết & Tiền Tệ', slots: {} },
  tab_equipment: { name: 'Binh Khí & Thần Cốt', slots: {} }
};

// AFTER:
export const stashTabs = {
  tab_general: { name: 'Kho Chung', slots: {} },
  tab_currency: { name: 'Tiền Tệ', slots: {} },
  tab_equipment: { name: 'Trang Bị', slots: {} }
};
```

#### 2. `client/webapp/js/ui/divine_vault_modal.js`
- **Line 203**:
```html
<!-- BEFORE: -->
<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>

<!-- AFTER: -->
<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>
```
- **Lines 131, 138, 145 & 260**:
Add `shortTitle` to `LORE_SCREENS`:
```javascript
// In LORE_SCREENS:
{ id: 'loading_forsaken_shore', titleVi: 'Bờ Biển Tử Địa', shortTitle: 'Bờ Biển', ... },
{ id: 'loading_eldritch_crypt', titleVi: 'Mật Ngục Tế Cốt', shortTitle: 'Mật Ngục', ... },
{ id: 'banner_deadlands_panorama', titleVi: 'Hoang Vực Xương Trắng', shortTitle: 'Hoang Vực', ... }

// In line 260:
${item.shortTitle || item.titleVi}
```

#### 3. `client/webapp/js/ui/meridian_vault.js`
Line 207:
```html
<!-- BEFORE: -->
<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: -->
<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>
```

#### 4. `client/webapp/js/ui/character_equipment.js`
Line 156:
```html
<!-- 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>
```

#### 5. `client/webapp/js/ui/seasonal_reset.js`
Lines 24-27 and 113:
```javascript
// BEFORE:
export let seasonStashTabs = [
  { id: 'ro_tab_01', name: '[Chỉ Rút - Mùa 1] Kho Chung', isRemoveOnly: true, items: [] },
  { id: 'std_tab_01', name: 'Kho Standard Chuẩn', isRemoveOnly: false, items: [] }
];
...
btn.innerHTML = `${tab.isRemoveOnly ? '🔒 <span class="text-amber-200">[CHỈ RÚT]</span>' : '📁'} ${tab.name} (${tab.items.length})`;

// AFTER:
export let seasonStashTabs = [
  { id: 'ro_tab_01', name: 'Chỉ Rút', isRemoveOnly: true, items: [] },
  { id: 'std_tab_01', name: 'Vĩnh Cửu', isRemoveOnly: false, items: [] }
];
...
btn.innerHTML = `${tab.isRemoveOnly ? '🔒' : '📁'} ${tab.name}`;
```

#### 6. `client/webapp/js/ui/story_quest_board.js`
Line 160:
```html
<!-- 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}">Tiếp Nhận</button>`
```

#### 7. `client/webapp/js/ui/worldmap_dungeons.js`
Line 88:
```javascript
// 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>
```

#### 8. `client/webapp/js/ui/npc_dialogue_catalog.js`
Remove parenthetical suffixes from choices:
- Line 58: `'Đưa đao đây, ta nhận khế ước săn mồi.'`
- Line 70: `'Chờ xem ta xé xác chúng rồi quay lại.'`
- Line 86: `'Mở Rương Hắc Thị an toàn.'`
- Line 87: `'Mở Chợ Đen Hoang Vực trao đổi.'`
- Line 100: `'Khảm Cổ Cốt Ấn và đúc U Minh Cốt Đinh.'`
- Line 113: `'Mở Huyết Cốt Ma Đồ tu luyện.'`
- Line 126: `'Dâng hũ Hỗn Nguyên Huyết Tửu đổi phương thuốc.'`

#### 9. `client/webapp/templates/*.html` (Legacy Static Files Synchronization)
- `forge_modal.html`:
  - Line 54: Change `"Phân Giải Trang Bị Rác (+8 Bụi)"` to `"Phân Giải"`
  - Line 87: Change `"Đập Tà Huyết Hủ Hóa (Thử Vận May)"` to `"Hủ Hóa"`
- `vault_modal.html`:
  - Line 9: Change `"🏛️ Kỳ Trân Các"` to `"🏛️ Chợ"`
  - Line 10: Change `"🛡️ Rương Bang Hội"` to `"🛡️ Rương Bang"`
  - Line 11: Change `"📜 Chỉ Số Tu Vi"` to `"📜 Chỉ Số"`
- `megashop_modal.html`:
  - Line 46: Change `"🪙 Huyết Cổ Tệ"` to `"🪙 Cổ Tệ"`
  - Line 49: Change `"⚔️ Tàn Binh & Giáp"` to `"⚔️ Trang Bị"`
  - Line 52: Change `"📦 Cổ Man Cốt Hạp"` to `"📦 Cốt Hạp"`
  - Line 55: Change `"🎒 Túi Sinh Tồn"` to `"🎒 Túi Đồ"`
- `divine_vault_modal.html`:
  - Line 19: Change `"Cổ Cốt Huyết Thạch"` to `"Cổ Cốt"`
  - Line 20: Change `"Màn Hình Chờ & Bối Cảnh"` to `"Bối Cảnh"`

---

## 5. Verification Method

1. **Unit Test Suite**:
   ```bash
   python -m unittest tests/unit/test_webapp_localization_engine.py
   ```
   *Expected Result*: Ran 16 tests, OK (exit code 0).
2. **E2E Test Suite**:
   ```bash
   pytest tests/e2e/test_ui_typography_i18n_wiki_streamlining_e2e.py -v
   ```
   *Expected Result*: 60 passed in ~0.27s (exit code 0).
3. **Hygiene Lint**:
   ```bash
   python tools/lint/check_code_and_doc_hygiene.py --strict
   ```
   *Expected Result*: Exit code 0, all files respect hard caps.
4. **Targeted Substring Invalidation Check**:
   Grep across `client/webapp/` for forbidden patterns:
   ```bash
   # Check for parenthetical bilingual button formats
   grep -rn "([A-Za-z0-9 ]*)" client/webapp/templates/
   # Verify button word counts in target UI scripts
   ```
   *Pass Condition*: Zero matches inside `<button>` tags or dynamic button template interpolations.
