# 58. Đặc Tả Kiến Trúc & Thiết Kế Kỹ Thuật: Máy Trạng Thái Quản Lý Vòng Đời Nhân Vật (Character Lifecycle State Machine - BotLifecycleFSM) & Triệt Tiêu Xung Đột Priority Tại Hideout (Build 6AA2213C)

> **Mã Tài Liệu**: `SPEC-DOC-58-CHARACTER-MANAGEMENT-STATE-MACHINE-20260915`  
> **Mốc Thời Gian**: `15/09/2026 - 04:45:00` (UTC+7)  
> **Phiên Bản Game Tham Chiếu**: Path of Exile 2 v0.5.5+ (PE TimeDateStamp `0x6AA2213C`, x64 Windows Client)  
> **Khu Vực Thực Địa Tham Chiếu**: `Shoreline Hideout` $\longleftrightarrow$ `Endgame Maps` (Waystone Tier XIV–XVI, Monster Level 80+)  
> **Nhân Vật Tham Chiếu**: `BEONGUSI#3653` — Monk / Martial Artist Chaos Inoculation (Level 90, `HP 1/1`, `ES 4713/4713` ~ `5656/5656`, `Ward 240/240`, `Mana 876/876`, `Spirit 7/147`, Quarterstaff CI Build)  
> **Trạng Thái Tài Liệu**: `[PRE-IMPLEMENTATION ARCHITECTURE SPECIFICATION]` (Giai đoạn Tiền Thực Thi - Tuân thủ nghiêm ngặt Rule 6)  
> **Tác Giả**: Dedicated Sub-Agent Documentation & Architecture Specialist (AutoPOE2)  
> **Tuân Thủ Quy Chuẩn**: Rule 1 (Two-Tier Asymmetric Architecture), Rule 2 (Context 2026), Rule 4 (Standardized Report), Rule 6 (Pre-Implementation Architecture Spec), Rule 8 (4-Step RCA & Anti-Symptom Patching), Rule 9 (Empirical DoD), Rule 10 (Zero-Drift Code-Doc Contract), Rule 11 (Automated Mock Harness), Rule 12 (Global Invariant Sweep), Rule 14 (Zero Mock Data - 100% Authentic Real Data)  
> **Tài Liệu Căn Cứ Trước**:
> - [`docs/development/50_two_tier_asymmetric_hybrid_architecture_specification.md`](./50_two_tier_asymmetric_hybrid_architecture_specification.md) (Kiến trúc Bất đối xứng Hai Tầng Hot/Cold Path 2026)
> - [`docs/development/56_spec_atlas_node_selector_and_map_device_orchestration.md`](./56_spec_atlas_node_selector_and_map_device_orchestration.md) (Bộ Điều Phối Atlas Node Selector & Nạp Precursor Tablet)
> - [`docs/development/48_closed_loop_map_runner_waystone_row1_farm.md`](./48_closed_loop_map_runner_waystone_row1_farm.md) (Vòng Lặp Tự Động Mở & Chạy Map Khép Kín FSM)
> - [`docs/development/29_botbrain_priority_fsm_pickit_and_closed_farming_loop.md`](./29_botbrain_priority_fsm_pickit_and_closed_farming_loop.md) (BotBrain Priority Arbiter & Action Handlers)
> - [`docs/development/47_auto_respawn_coordinates_and_resurrection_fsm_rca.md`](./47_auto_respawn_coordinates_and_resurrection_fsm_rca.md) (Auto-Respawn FSM & Hồi Sinh An Toàn)

---

## 1. Tổng Quan & Phân Tích Nguyên Nhân Gốc Rễ (Executive Summary & Root-Cause Analysis - RCA)

### 1.1. Hiện Trạng & Phản Ánh Của Người Dùng (User Incident)
Người dùng vận hành phản ánh thực trạng nghiêm trọng:
> *"Phải làm state machine cho quản lý nhân vật chứ, cứ chắp vá thế mãi à :(".  
> "Hiện tại, khi bật F8 ở Hideout, hệ thống không có Character State Machine quản lý vòng đời nhân vật. Các handler (QuestNavigator, UnstuckHandler, MapDeviceHandler) cạnh tranh priority hỗn loạn dẫn đến QuestNavigator đề xuất Explore (IDLE 1000) trong Hideout, chạy đâm đầu vào tường và UnstuckHandler đề xuất Dodge Roll (Spacebar) liên tục."*

Hiện tượng thực tế khi người dùng nhấn phím **F8 (Toggle Bot)** tại Hideout:
1. Nhân vật bắt đầu bước đi vô định, đâm sầm vào bờ tường, đồ nội thất hoặc Map Device tại Hideout.
2. Sau khoảng 10 giây bị chặn bởi vật cản địa hình Hideout, nhân vật đột ngột lộn nhào (Dodge Roll - Spacebar) liên tục, giật cục và thậm chí cố gắng bấm phím mở Town Portal (`.`) ngay trong khi đang đứng tại Hideout!

---

### 1.2. Điều Tra 4 Bước RCA Tận Gốc (Mandatory 4-Step RCA)

Áp dụng quy trình RCA nghiêm ngặt theo **Rule 8 (Anti-Symptom Patching Protocol)**:

#### Bước 1: Tái Hiện & Truy Vết Chuỗi Gọi Hàm (Reproduce & Trace Call Graph)
Khi người dùng kích hoạt phím `F8` trong vòng lặp chính ([`src/core/main.cpp`](../../src/core/main.cpp#L1065-L1073)):
- Biến cờ `allowPhysicalMove` được bật thành `true`.
- Vòng lặp Hot Path 120Hz gọi hàm điều phối [`botBrain.Process(samplePacket, kmbox, tickMs)`](../../src/core/main.cpp#L1274).
- Tại mỗi tick, `BotBrain` thu thập đề xuất `ActionProposal` từ tất cả các handler được đăng ký:
  ```
  BotBrain Handlers:
  ├── UnstuckHandler::Propose()       ──> Trả về {} (nếu chưa kẹt)
  ├── ComboManager::Propose()         ──> Trả về {} (không có quái vật trong Hideout)
  ├── LootController::Propose()       ──> Trả về {} (không có vật phẩm rơi trên sàn)
  ├── AreaEventHandler::Propose()     ──> Trả về {} (không có sự kiện interactive)
  ├── InventoryHandler::Propose()     ──> Trả về {} (chưa nhận lệnh Stash từ IPC)
  ├── NpcInteractionHandler::Propose()──> Trả về {} (chưa nhận lệnh NPC từ IPC)
  ├── MapDeviceHandler::Propose()     ──> Trả về {} (chưa nhận lệnh StartMapDevice)
  └── QuestNavigator::Propose()       ──> PHÁT SINH LỖI TẠI ĐÂY!
  ```
- Truy vết vào mã nguồn [`QuestNavigator::Propose`](../../src/core/navigation/quest_navigator.cpp#L812-L826):
  ```cpp
  if (m_config.autoPatrol || m_config.enabled) {
      std::string areaCodeStr(packet.area.areaCode);
      std::string areaNameStr(packet.area.areaName);
      bool isTown = (!areaCodeStr.empty() && (areaCodeStr.find("town") != std::string::npos || areaCodeStr.find("Town") != std::string::npos)) ||
                    (!areaNameStr.empty() && (areaNameStr.find("Encampment") != std::string::npos ||
                                              areaNameStr.find("Caravan") != std::string::npos ||
                                              areaNameStr.find("Hideout") != std::string::npos));

      ActionProposal p{};
      p.kind = BotActionKind::Explore;   // <--- BUG 1: Gán kind = Explore thay vì Idle!
      p.priority = isTown ? bot_priority::IDLE : bot_priority::EXPLORE; // priority = 1000
      p.priorityName = isTown ? "IDLE" : "EXPLORE";
      p.distance = 100.0f;
      return p;
  }
  ```
- Do các handler khác đều trả về `priority = 0`, đề xuất của `QuestNavigator` với `priority = 1000` trở thành **người chiến thắng duy nhất**.
- `BotBrain::Process` gọi [`QuestNavigator::Execute`](../../src/core/navigation/quest_navigator.cpp#L835):
  ```cpp
  if (chosen.kind == BotActionKind::SwitchArea || chosen.kind == BotActionKind::Explore) {
      return Update(packet, kmbox, nowMs); // <--- BUG 2: Kích hoạt thuật toán tìm đường trong Hideout!
  }
  ```
- Hàm `Update` tính toán vector di chuyển NavMesh và phát lệnh WASD/Mouse liên tục. Nhân vật di chuyển đâm đầu vào tường Hideout.
- Sau $10.000\text{ms}$ (`failMovementCheckIntervalMs`), nhân vật di chuyển $< 3.0\text{u}$ (`minMovementDelta`).
- [`UnstuckHandler::Propose`](../../src/core/brain/unstuck_handler.cpp#L95-L104) kích hoạt:
  ```cpp
  m_reason = UnstuckReason::MovementStuck;
  ActionProposal p{};
  p.kind = BotActionKind::Unstuck;
  p.priority = bot_priority::UNSTUCK; // Priority = 8000!
  ```
- `UnstuckHandler` cướp quyền hoàn toàn (8000 > 1000). Trong [`UnstuckHandler::Execute`](../../src/core/brain/unstuck_handler.cpp#L155-L165):
  Tại bước phục hồi thứ 2 (`m_recoveryAttempts == 1`), nó phát lệnh:
  `keybd_event(VK_SPACE, 0, 0, 0);` $\implies$ **Dodge Roll lộn nhào điên cuồng trong Hideout!**

#### Bước 2: Phân Tích Bất Biến Bị Vi Phạm (Invariant Invalidation Analysis)
1. **Vi phạm Bất biến Phân cấp Thẩm quyền (Hierarchical Authority Invariant)**: Hệ thống sử dụng mô hình "Flat Priority Arbiter" (Trọng tài Ưu tiên Đẳng cấp Phẳng) cho toàn bộ vòng đời. Các hành động vi mô (Micro-Actions: Dodge, Flask, Attack, Loot, Step) bị đặt ngang hàng với trạng thái vĩ mô của nhân vật (Macro State: Đang ở Làng, Đang ở Hideout, Đang tải map, Đang đánh nhau trong map).
2. **Vi phạm Bất biến Hideout Bất động (Zero-Movement Hideout Invariant)**: Trong Hideout hoặc Town, khi chưa có kế hoạch di chuyển mục tiêu rõ ràng (như tiếp cận Stash hoặc tiếp cận Map Device), nhân vật BẮT BUỘC PHẢI ĐỨNG YÊN 100%. Mọi hành vi thám hiểm bản đồ (`Explore`), tự động tuần tra (`AutoPatrol`) và gỡ kẹt né đòn (`Dodge Roll Unstuck`) đều là hành vi bất hợp lệ.

#### Bước 3: Đề Xuất Tái Cấu Trúc Tận Gốc (Structural Architectural Fix)
Loại bỏ hoàn toàn cách tiếp cận chắp vá (không chỉ sửa `p.kind = Idle` ở một dòng lẻ trong `QuestNavigator`).  
**Thiết lập Máy Trạng Thái Quản Lý Vòng Đời Nhân Vật Chuẩn Mực (`BotLifecycleFSM` / `CharacterLifecycleManager`)** làm tầng giám sát tối cao (Supervisor Layer) nằm phía trên `BotBrain Priority Arbiter`.

#### Bước 4: Khóa Chặn Bằng Invariant Assertion (Contract Enforcement)
Tạo mặt nạ phân quyền hành động (`AllowedActionMask`). Mọi hành động do các handler đề xuất BẮT BUỘC phải đi qua bộ lọc bitmask của trạng thái vòng đời hiện tại trước khi được `BotBrain` xem xét phân định priority.

---

## 2. Tuyên Ngôn Kiến Trúc & Thiết Kế Hai Tầng (Two-Tier Asymmetric Architecture 2026)

Tuân thủ nguyên tắc thiết kế bất đối xứng chuẩn mực 2026 quy định tại [`Doc 50`](./50_two_tier_asymmetric_hybrid_architecture_specification.md):

```
┌─────────────────────────────────────────────────────────────────────────────────────────────┐
│                          TIER 2: COLD PATH (1 - 30Hz) - PYTHON 3.11 COMPANION                │
│                                                                                             │
│   ┌────────────────────────┐    ┌────────────────────────┐    ┌─────────────────────────┐   │
│   │ Atlas Strategy Planner │    │ Stash & Inventory OCR  │    │ Lifecycle Supervisor    │   │
│   │ (Node Selection, Buff) │    │ (Waystone/Tablet Eval) │    │ (Farm Loop Coordinator) │   │
│   └───────────┬────────────┘    └───────────┬────────────┘    └────────────┬────────────┘   │
│               │                             │                              │                │
│               └──────────────────────┬──────┴──────────────────────────────┘                │
│                                      ▼                                                      │
│                   SPSC Ring Buffer CommandPacket (OpCodes 5, 7, 9, 10, 11)                   │
└──────────────────────────────────────┬──────────────────────────────────────────────────────┘
                                       │ Lock-Free IPC (Mechanical Sympathy 64B Slots)
┌──────────────────────────────────────▼──────────────────────────────────────────────────────┐
│                          TIER 1: HOT PATH (120Hz) - C++23 CORE ENGINE                       │
│                                                                                             │
│   ┌─────────────────────────────────────────────────────────────────────────────────────┐   │
│   │                     CharacterLifecycleManager (BotLifecycleFSM)                     │   │
│   │  Giám sát trạng thái vĩ mô: UNINITIALIZED ↔ HIDEOUT ↔ MAP ↔ RECOVERY                │   │
│   │  Sinh ra: Current Macro State & AllowedActionMask (uint32_t)                       │   │
│   └──────────────────────────────────────────┬──────────────────────────────────────────┘   │
│                                              ▼                                              │
│   ┌─────────────────────────────────────────────────────────────────────────────────────┐   │
│   │                    BotBrain Priority Arbiter (Gated by AllowedMask)                 │   │
│   │  Lọc bỏ 100% đề xuất vi phạm trạng thái vĩ mô TRƯỚC KHI so sánh Priority!           │   │
│   └───────┬────────────┬────────────┬────────────┬────────────┬───────────┬─────────────┘   │
│           │            │            │            │            │           │                 │
│           ▼            ▼            ▼            ▼            ▼           ▼                 │
│      ReflexMgr     Unstuck      ComboMgr     LootCtrl     MapDevice    QuestNav             │
│       (120Hz)     (In-Map Only) (Combat)     (Pickit)     (Hideout)   (NavMesh)             │
│                                                                                             │
│   KMBox Net Hardware / Emulation Input Sink (< 8.33ms Deterministic Latency)                │
└─────────────────────────────────────────────────────────────────────────────────────────────┘
```

- **Tier 1 (Hot Path 120Hz C++23)**:
  - `CharacterLifecycleManager` thực thi logic chuyển trạng thái FSM vĩ mô dựa trên Telemetry sống động (RAM RPM O(1) Snapshot) và nhịp tim Watchdog cứng.
  - Cung cấp `AllowedActionMask` để khóa chặt không cho bất kỳ handler vi mô nào phát lệnh trái phép.
  - Bảo đảm phản xạ sinh tồn (Auto-Flask, Emergency Logout) hoạt động độc lập 100% không phụ thuộc trạng thái FSM.
- **Tier 2 (Cold Path 1–30Hz Python Companion)**:
  - Giám sát toàn cảnh vòng lặp farm, phân tích thị giác OCR túi đồ và Atlas Tree.
  - Gửi chỉ thị điều phối vĩ mô qua SPSC Ring Buffer: `START_FARM_LOOP`, `PAUSE_FARM_LOOP`, `FORCE_LIFECYCLE_STATE`.
  - Không can thiệp trực tiếp vào xung nhịp điều khiển micro-input của C++.

---

## 3. Chi Tiết Máy Trạng Thái Quản Lý Vòng Đời Nhân Vật (BotLifecycleFSM)

### 3.1. Danh Mục 11 Trạng Thái Vĩ Mô (Macro States)

Máy trạng thái `BotLifecycleFSM` bao gồm đúng **11 trạng thái vĩ mô khép kín**, bao quát toàn bộ chu trình sống của nhân vật từ lúc khởi động, ở Hideout, nạp map, chiến đấu, về làng cho đến xử lý sự cố:

```cpp
enum class CharacterLifecycleState : uint8_t {
    UNINITIALIZED_OR_LOADING = 0, // Khởi tạo, chờ nạp game / Loading Screen
    HIDEOUT_IDLE             = 1, // Đứng yên tuyệt đối tại Hideout, chờ lệnh
    HIDEOUT_STASHING         = 2, // Đang mở hòm đồ Stash, cất giữ currency & loot
    HIDEOUT_PREPARE_MAP      = 3, // Đang kiểm tra/chế tác Waystone & Precursor Tablet
    HIDEOUT_MAP_DEVICE_APPROACH = 4, // Tiếp cận Map Device theo tọa độ thực thể RAM
    HIDEOUT_MAP_DEVICE_ACTIVATE = 5, // Mở UI Map Device, chọn Node Atlas, socket & bật Map
    HIDEOUT_ENTER_PORTAL     = 6, // Định vị portal thực thể và click bước vào Map
    MAP_LOADING_GRACE        = 7, // Màn hình tải Map xong, bảo vệ Grace Period bất tử
    MAP_FARMING_COMBAT       = 8, // Chạy map, diệt quái, nhặt đồ, né đòn, dọn boss
    MAP_COMPLETED_PORTAL_OUT = 9, // Hoàn thành mục tiêu map, mở portal về Hideout
    EMERGENCY_RECOVERY       = 10 // Xử lý tử trận (Respawn), mất kết nối (AutoLogin)
};
```

---

### 3.2. Bảng Đặc Tả Chi Tiết Từng Trạng Thái (State Specification Matrix)

| Trạng Thái (State) | Ý Nghĩa Vận Hành | Tiền Điều Kiện Vào (Entry Conditions) | Hành Vi CẤM TUYỆT ĐỐI (Forbidden Actions) | Hành Vi Được Phép (Allowed Actions) | Điều Kiện Rời Khỏi (Exit / Transition Triggers) | Watchdog Timeout |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| **0. UNINITIALIZED_OR_LOADING** | Đang tải màn hình (Loading Screen), chưa đọc được Player Pointer hoặc Area Code. | Khởi động bot HOẶC `areaLoadTimestampMs` thay đổi HOẶC màn hình đen chuyển cảnh. | CẤM mọi thao tác phím/chuột. CẤM gửi gói input KMBox. CẤM di chuyển. | Chỉ đọc bộ nhớ RAM O(1), lắng nghe LogSensor kiểm tra kết thúc tải trang. | - Đọc được Area là `Hideout` $\implies$ sang `HIDEOUT_IDLE`.<br>- Đọc được Area là Map Endgame $\implies$ sang `MAP_LOADING_GRACE`.<br>- Mất kết nối/văng màn hình đăng nhập $\implies$ sang `EMERGENCY_RECOVERY`. | 45.000ms (Nếu quá 45s kẹt loading $\implies$ Killswitch) |
| **1. HIDEOUT_IDLE** | Nhân vật đứng yên 100% tại Hideout. Chờ lệnh người dùng hoặc chuẩn bị chu trình farm. | Vừa tải xong vào Hideout HOẶC người dùng nhấn F8 bật bot HOẶC vừa hoàn tất Stash. | **CẤM DI CHUYỂN (WASD/Click). CẤM Explore. CẤM Dodge Roll (Space). CẤM Unstuck. CẤM mở Portal.** | Đứng yên tại tọa độ hiện tại. Tiếp nhận lệnh SPSC Ring Buffer. Đánh giá trạng thái túi đồ. | - Túi đồ đầy rác/loot cần cất $\implies$ sang `HIDEOUT_STASHING`.<br>- Bật Auto-Farm và cần chuẩn bị Waystone $\implies$ sang `HIDEOUT_PREPARE_MAP`.<br>- Đã có Waystone sẵn sàng trong túi đồ $\implies$ sang `HIDEOUT_MAP_DEVICE_APPROACH`.<br>- Người dùng tắt F8 $\implies$ Giữ nguyên IDLE. | $\infty$ (Chế độ chờ nhàn rỗi) |
| **2. HIDEOUT_STASHING** | Tương tác với hòm đồ Stash trong Hideout để cất Currency, Waystone, Uniques. | Chuyển từ `HIDEOUT_IDLE` khi túi đồ đầy loot sau khi chạy map về. | CẤM chạy lung tung. CẤM cast skill chiến đấu. CẤM Dodge Roll. CẤM mở portal. | Điều khiển `InventoryHandler` FSM: Tiếp cận Stash $\rightarrow$ Mở UI Stash $\rightarrow$ Ctrl+Click cất đồ theo filter $\rightarrow$ Đóng UI. | - `InventoryHandler` hoàn tất chu trình Stash $\implies$ sang `HIDEOUT_PREPARE_MAP`.<br>- Thất bại tương tác Stash sau 3 lần thử $\implies$ sang `EMERGENCY_RECOVERY`. | 20.000ms |
| **3. HIDEOUT_PREPARE_MAP** | Kiểm tra hàng 1 túi đồ (Row 0) xem có Waystone hợp lệ và Precursor Tablet không. | Chuyển từ `HIDEOUT_IDLE` hoặc `HIDEOUT_STASHING` khi chuẩn bị mở map mới. | CẤM di chuyển ra xa Map Device. CẤM cast skill chiến đấu. CẤM mở portal. | Quét quang học OCR hoặc RAM cấu trúc túi đồ Row 0. Kiểm tra Tablet trong túi đồ. | - Đã có ít nhất 1 Waystone hợp lệ ở Row 0 $\implies$ sang `HIDEOUT_MAP_DEVICE_APPROACH`.<br>- Hết sạch Waystone trong túi đồ $\implies$ Báo động còi/log, chuyển về `HIDEOUT_IDLE` dừng farm. | 5.000ms |
| **4. HIDEOUT_MAP_DEVICE_APPROACH** | Di chuyển tiếp cận Map Device trong Hideout dựa trên tọa độ thực thể RAM. | Đã chuẩn bị xong Waystone, khoảng cách tới Map Device $> 18.0\text{u}$. | CẤM dùng Spacebar Dodge Roll để gỡ kẹt. CẤM cast skill chiến đấu. CẤM mở portal. | Di chuyển có kiểm soát (Micro-Step A* hoặc Bézier) hướng về phía Map Device Entity ($X, Y$). Trượt tiếp tuyến nếu cọ tường. | - Khoảng cách tới Map Device $\le 18.0\text{u}$ (tương tác được) $\implies$ sang `HIDEOUT_MAP_DEVICE_ACTIVATE`.<br>- Không tìm thấy Map Device trong RAM $\implies$ sang `EMERGENCY_RECOVERY`. | 15.000ms (Nếu kẹt đường quá 15s $\implies$ Recovery) |
| **5. HIDEOUT_MAP_DEVICE_ACTIVATE** | Mở giao diện Map Device, chọn Node Atlas, nạp Waystone + Tablet và kích hoạt. | Nhân vật đã đứng sát Map Device ($\le 18.0\text{u}$). | CẤM di chuyển WASD. CẤM cast skill. CẤM Dodge Roll. CẤM click ra ngoài UI. | Thực thi `MapDeviceHandler` FSM (Doc 48 & Doc 56): Click mở UI $\rightarrow$ SelectAtlasNode $\rightarrow$ Socket Waystone $\rightarrow$ Socket Tablet $\rightarrow$ Click Activate. | - Nút Activate được nhấn thành công, Map Device bắt đầu xoay mở cổng $\implies$ sang `HIDEOUT_ENTER_PORTAL`.<br>- UI Map Device bị lỗi không mở được $\implies$ sang `EMERGENCY_RECOVERY`. | 25.000ms |
| **6. HIDEOUT_ENTER_PORTAL** | Định vị cánh cổng Portal quanh Map Device và click bước vào để nạp Map. | Map Device đã Activate, các cánh cổng Portal màu xanh mở ra. | CẤM chạy xa khỏi cụm Portal. CẤM spam click mù. CẤM Dodge Roll. | Quét danh sách Entity RAM tìm thực thể Portal (`name` chứa "MapWorlds" hoặc "Portal", `type == 3`). Click chuột trái lên tâm Portal. | - Phát hiện màn hình bắt đầu chuyển cảnh nạp map $\implies$ sang `UNINITIALIZED_OR_LOADING`.<br>- Không tìm thấy Portal entity sau 8s $\implies$ sang `EMERGENCY_RECOVERY`. | 12.000ms |
| **7. MAP_LOADING_GRACE** | Vừa tải xong vào trong Map. Tận dụng thời gian ân hạn Grace Period bất tử. | Vừa thoát màn hình tải trang vào khu vực Map Endgame. | CẤM di chuyển vội vã. CẤM cast skill bừa bãi làm mất Grace Period khi xung quanh chưa phân tích xong. | Đứng yên tận dụng Grace Buff (30s). Đồng bộ NavMesh địa hình. Quét quái vật xung quanh qua RAM Entity List. Bật Buff Aura nếu cần. | - RAM Telemetry & NavMesh sẵn sàng, không có quái vật cắn sát người $\implies$ sang `MAP_FARMING_COMBAT`.<br>- Bị quái tấn công mất máu $\implies$ Ngay lập tức sang `MAP_FARMING_COMBAT`. | 5.000ms (Tối đa 5s bảo vệ Grace) |
| **8. MAP_FARMING_COMBAT** | Chạy map chính thức: diệt quái, né đòn, nhặt đồ, thám hiểm, hạ Boss Endgame. | Chuyển từ `MAP_LOADING_GRACE` khi nhân vật sẵn sàng chiến đấu. | CẤM mở portal về làng khi chưa hoàn thành map (trừ tình huống khẩn cấp Chicken/Emergency). | Kích hoạt toàn bộ sức mạnh của `BotBrain Priority Arbiter`: Reflex (Flask/Dodge), Combat (Combo/Kite), Pickup (Loot), AreaEvent, Explore (QuestNav). | - Thỏa mãn điều kiện xong map (Hạ Boss + nhặt loot xong HOẶC dọn sạch map) $\implies$ sang `MAP_COMPLETED_PORTAL_OUT`.<br>- Nhân vật tử trận (`HP == 0`) $\implies$ sang `EMERGENCY_RECOVERY`.<br>- Hết bình máu/nguy cấp $\implies$ sang `EMERGENCY_RECOVERY`. | 900.000ms (15 phút tối đa cho 1 map) |
| **9. MAP_COMPLETED_PORTAL_OUT** | Mở Town Portal bằng phím chuẩn `.` và click bước qua portal để thoát về Hideout. | Hoàn thành mục tiêu map (Boss Slain hoặc Clear Ratio đạt chuẩn). | CẤM tiếp tục chạy săn quái. CẤM nhặt đồ rác. | Dừng di chuyển. Bấm phím mở Town Portal `.` (`VK 0xBE` / `HID 0x37`). Quét tìm Portal entity vừa mở trong bán kính $30\text{u}$. Click tương tác bước qua portal. | - Phát hiện game chuyển cảnh nạp màn hình $\implies$ sang `UNINITIALIZED_OR_LOADING`.<br>- Portal không mở được sau 3 lần bấm $\implies$ Cưỡng chế Chicken Logout $\implies$ sang `EMERGENCY_RECOVERY`. | 15.000ms |
| **10. EMERGENCY_RECOVERY** | Phục hồi sau sự cố: Nhân vật tử trận, mất kết nối, kẹt vòng lặp hoặc timeout. | Kích hoạt khi có bất thường ở bất kỳ trạng thái nào (HP = 0, Timeout, Disconnect). | CẤM tiếp tục thực hiện hành động của trạng thái cũ đang bị lỗi. | - Nếu nhân vật tử trận: Kích hoạt Auto-Respawn tại $Y = 73.61\%$ (Doc 47) hồi sinh về Hideout.<br>- Nếu mất kết nối: Kích hoạt AutoLogin FSM (Doc 39).<br>- Nếu kẹt timeout: Giải phóng input, dừng di chuyển, mở portal thoát hiểm. | - Nhân vật đã hồi sinh hoặc nạp thành công vào Hideout $\implies$ sang `HIDEOUT_IDLE`.<br>- Sau 3 lần phục hồi thất bại liên tiếp $\implies$ Cưỡng chế PANIC_STOP dừng bot an toàn. | 30.000ms |

---

## 4. Sơ Đồ Chuyển Trạng Thái Toàn Diện (Mermaid State Diagram v2)

```mermaid
stateDiagram-v2
    [*] --> UNINITIALIZED_OR_LOADING: Khởi động Bot / Game Launch

    state UNINITIALIZED_OR_LOADING {
        [*] --> WaitingForAreaLoad
        WaitingForAreaLoad --> AreaIdentified: RPM đọc AreaCode & PlayerPtr hợp lệ
    }

    UNINITIALIZED_OR_LOADING --> HIDEOUT_IDLE: Area == Hideout / Town
    UNINITIALIZED_OR_LOADING --> MAP_LOADING_GRACE: Area == Map Endgame
    UNINITIALIZED_OR_LOADING --> EMERGENCY_RECOVERY: Loading Timeout (>45s) / Disconnect

    state HIDEOUT_IDLE {
        [*] --> StandStill100Percent
        note right of StandStill100Percent
            BẤT BIẾN INV-CHAR-FSM-01:
            - Zero Movement (WASD = 0)
            - CẤM QuestNav Explore
            - CẤM Unstuck Dodge Roll
        end note
        StandStill100Percent --> EvaluateInventory: Nhấn F8 (Bật Auto-Farm)
    }

    HIDEOUT_IDLE --> HIDEOUT_STASHING: Túi đồ đầy loot / cần cất đồ
    HIDEOUT_IDLE --> HIDEOUT_PREPARE_MAP: Túi đồ sạch, sẵn sàng farm
    HIDEOUT_IDLE --> HIDEOUT_IDLE: F8 OFF (Tạm dừng bot)

    state HIDEOUT_STASHING {
        ApproachStash --> OpenStashUI
        OpenStashUI --> TransferLoot: Ctrl+Click theo Pickit
        TransferLoot --> CloseStashUI
    }
    HIDEOUT_STASHING --> HIDEOUT_PREPARE_MAP: Cất đồ xong (Inventory Clean)
    HIDEOUT_STASHING --> EMERGENCY_RECOVERY: Kẹt Stash UI (>20s)

    state HIDEOUT_PREPARE_MAP {
        ScanRow0Waystones --> VerifyTabletCount
        VerifyTabletCount --> ReadyToApproach: Có ít nhất 1 Waystone
        VerifyTabletCount --> OutOfWaystones: Hết sạch Waystone Row 0
    }
    HIDEOUT_PREPARE_MAP --> HIDEOUT_MAP_DEVICE_APPROACH: ReadyToApproach
    HIDEOUT_PREPARE_MAP --> HIDEOUT_IDLE: OutOfWaystones (Báo động dừng farm)

    state HIDEOUT_MAP_DEVICE_APPROACH {
        LocateMapDeviceRAM --> MicroStepMove
        MicroStepMove --> WithinInteractRadius: Khoảng cách <= 18.0u
    }
    HIDEOUT_MAP_DEVICE_APPROACH --> HIDEOUT_MAP_DEVICE_ACTIVATE: WithinInteractRadius
    HIDEOUT_MAP_DEVICE_APPROACH --> EMERGENCY_RECOVERY: Kẹt đường đi (>15s)

    state HIDEOUT_MAP_DEVICE_ACTIVATE {
        OpenDeviceUI --> SelectAtlasNode: Doc 56 (Chọn Node Atlas)
        SelectAtlasNode --> SocketTablet: Nạp Precursor Tablet vào Tháp
        SocketTablet --> SocketWaystone: Cắm Waystone Row 0
        SocketWaystone --> ClickActivateButton: Nhấn nút Activate mở cổng
    }
    HIDEOUT_MAP_DEVICE_ACTIVATE --> HIDEOUT_ENTER_PORTAL: Device Activated & Portals Spawning
    HIDEOUT_MAP_DEVICE_ACTIVATE --> EMERGENCY_RECOVERY: Activate Thất Bại (>25s)

    state HIDEOUT_ENTER_PORTAL {
        WaitForPortalEntities --> ScanBluePortalRAM
        ScanBluePortalRAM --> ClickPortalCenter: Bézier Click vào Portal
    }
    HIDEOUT_ENTER_PORTAL --> UNINITIALIZED_OR_LOADING: Clicked Portal -> Loading Screen
    HIDEOUT_ENTER_PORTAL --> EMERGENCY_RECOVERY: Portal Timeout (>12s)

    state MAP_LOADING_GRACE {
        HoldStillGracePeriod --> SynchronizeNavMesh
        SynchronizeNavMesh --> EnableCombatAuras: Grace Buff Active (<=5s)
    }
    MAP_LOADING_GRACE --> MAP_FARMING_COMBAT: NavMesh Ready & Buffs Ready
    MAP_LOADING_GRACE --> MAP_FARMING_COMBAT: Bị quái cắn mất máu (Grace Broken)

    state MAP_FARMING_COMBAT {
        note left of MAP_FARMING_COMBAT
            KÍCH HOẠT BOTBRAIN ARBITER:
            - Reflex: Flask (9000), Dodge (8500)
            - UnstuckHandler (8000)
            - ComboManager (7000)
            - LootController (6000)
            - QuestNavigator (4000)
        end note
        CombatLoop --> CheckMapGoal: Boss Slain / Full Clear
    }
    MAP_FARMING_COMBAT --> MAP_COMPLETED_PORTAL_OUT: Map Goal Achieved & Loot Finished
    MAP_FARMING_COMBAT --> EMERGENCY_RECOVERY: Tử trận (HP == 0) / Hết bình máu

    state MAP_COMPLETED_PORTAL_OUT {
        StopAndCheckSafety --> CastTownPortalKey: Phím '.' (VK 0xBE)
        CastTownPortalKey --> ClickExitPortal: Click bước vào Town Portal
    }
    MAP_COMPLETED_PORTAL_OUT --> UNINITIALIZED_OR_LOADING: Clicked Town Portal -> Loading Screen
    MAP_COMPLETED_PORTAL_OUT --> EMERGENCY_RECOVERY: Portal Fail (>15s) -> Chicken Logout

    state EMERGENCY_RECOVERY {
        DetectFailureType --> HandleDeath: HP == 0
        DetectFailureType --> HandleDisconnect: Mất kết nối
        DetectFailureType --> HandleTimeout: Kẹt FSM Timeout
        HandleDeath --> AutoRespawnButton: Click nút Hồi Sinh Y=73.61%
        HandleDisconnect --> AutoLoginRoutine: AutoLogin FSM Doc 39
        HandleTimeout --> ReleaseInputsAndReset: Xóa cờ kẹt, ngắt input
    }
    EMERGENCY_RECOVERY --> UNINITIALIZED_OR_LOADING: Respawn / Login hoàn tất
    EMERGENCY_RECOVERY --> [*]: Thất bại 3 lần liên tiếp (PANIC_STOP)
```

---

## 5. Ma Trận Phân Quyền Hành Động (Action Permission Matrix & AllowedActionMask)

Để giải quyết triệt để lỗi xung đột priority mà không cần can thiệp chắp vá vào từng handler riêng lẻ, `BotLifecycleFSM` thiết lập **Mặt Nạ Phân Quyền Hành Động (`AllowedActionMask`)** dạng bitmask 32-bit:

```cpp
namespace bot_action_mask {
    constexpr uint32_t NONE             = 0;
    constexpr uint32_t CHICKEN          = (1 << 1);  // BotActionKind::Chicken (10000)
    constexpr uint32_t FLASK            = (1 << 2);  // BotActionKind::Flask (9000)
    constexpr uint32_t DODGE            = (1 << 3);  // BotActionKind::Dodge (8500)
    constexpr uint32_t UNSTUCK          = (1 << 4);  // BotActionKind::Unstuck (8000)
    constexpr uint32_t EMERGENCY_ATTACK = (1 << 5);  // BotActionKind::EmergencyAttack (7500)
    constexpr uint32_t COMBAT           = (1 << 6);  // BotActionKind::Combat (7000)
    constexpr uint32_t AREA_EVENT       = (1 << 7);  // BotActionKind::AreaEvent (6500)
    constexpr uint32_t PICKUP           = (1 << 8);  // BotActionKind::Pickup (6000)
    constexpr uint32_t OPEN_CHEST       = (1 << 9);  // BotActionKind::OpenChest (5500)
    constexpr uint32_t WAIT_LOOT        = (1 << 10); // BotActionKind::WaitLoot (5000)
    constexpr uint32_t WAIT_BOSS        = (1 << 11); // BotActionKind::WaitBoss (4800)
    constexpr uint32_t EXPLORE          = (1 << 12); // BotActionKind::Explore (4000)
    constexpr uint32_t STASH            = (1 << 13); // BotActionKind::Stash (3500)
    constexpr uint32_t VENDOR           = (1 << 14); // BotActionKind::Vendor (3400)
    constexpr uint32_t SWITCH_AREA      = (1 << 15); // BotActionKind::SwitchArea (3000)
    constexpr uint32_t IDLE             = (1 << 16); // BotActionKind::Idle (1000)
    constexpr uint32_t NPC_INTERACT     = (1 << 17); // BotActionKind::NpcInteract (3300)
}
```

### 5.1. Ma Trận Cấp Phép Bitmask Theo Trạng Thái

```cpp
inline uint32_t GetAllowedActionMask(CharacterLifecycleState state) {
    switch (state) {
        case CharacterLifecycleState::UNINITIALIZED_OR_LOADING:
            // Đang tải trang: Khóa cứng 100% input! Chỉ cho phép Chicken khẩn cấp nếu đứt mạng
            return bot_action_mask::CHICKEN;

        case CharacterLifecycleState::HIDEOUT_IDLE:
            // BẤT BIẾN INV-CHAR-FSM-01: Nghiêm cấm di chuyển, cấm explore, cấm dodge roll!
            // Chỉ cho phép Idle tuyệt đối và phản xạ Flask nếu có tà khí gây mất máu
            return bot_action_mask::IDLE | bot_action_mask::FLASK;

        case CharacterLifecycleState::HIDEOUT_STASHING:
            // Chỉ cho phép hành động Stash và Vendor
            return bot_action_mask::STASH | bot_action_mask::VENDOR | bot_action_mask::IDLE;

        case CharacterLifecycleState::HIDEOUT_PREPARE_MAP:
            // Đang đọc và chuẩn bị túi đồ: Đứng yên
            return bot_action_mask::IDLE;

        case CharacterLifecycleState::HIDEOUT_MAP_DEVICE_APPROACH:
            // Chỉ cho phép di chuyển tiếp cận Map Device (SwitchArea/Interact)
            return bot_action_mask::SWITCH_AREA | bot_action_mask::IDLE;

        case CharacterLifecycleState::HIDEOUT_MAP_DEVICE_ACTIVATE:
            // Chỉ cho phép tương tác với Map Device UI
            return bot_action_mask::SWITCH_AREA | bot_action_mask::IDLE;

        case CharacterLifecycleState::HIDEOUT_ENTER_PORTAL:
            // Chỉ cho phép click bước vào cánh cổng Portal (SwitchArea)
            return bot_action_mask::SWITCH_AREA | bot_action_mask::IDLE;

        case CharacterLifecycleState::MAP_LOADING_GRACE:
            // Bảo vệ Grace Period: Cho phép Flask/Aura, CẤM di chuyển làm mất Grace
            return bot_action_mask::FLASK | bot_action_mask::IDLE;

        case CharacterLifecycleState::MAP_FARMING_COMBAT:
            // TRONG MAP: Mở toàn bộ quyền cho tất cả các handler chiến đấu & nhặt đồ!
            return bot_action_mask::CHICKEN | bot_action_mask::FLASK | bot_action_mask::DODGE |
                   bot_action_mask::UNSTUCK | bot_action_mask::EMERGENCY_ATTACK | bot_action_mask::COMBAT |
                   bot_action_mask::AREA_EVENT | bot_action_mask::PICKUP | bot_action_mask::OPEN_CHEST |
                   bot_action_mask::WAIT_LOOT | bot_action_mask::WAIT_BOSS | bot_action_mask::EXPLORE |
                   bot_action_mask::SWITCH_AREA | bot_action_mask::IDLE;

        case CharacterLifecycleState::MAP_COMPLETED_PORTAL_OUT:
            // Mở portal thoát về làng: Chỉ cho phép dùng portal và tự vệ sinh tồn nếu bị đánh
            return bot_action_mask::CHICKEN | bot_action_mask::FLASK | bot_action_mask::DODGE |
                   bot_action_mask::EMERGENCY_ATTACK | bot_action_mask::SWITCH_AREA | bot_action_mask::IDLE;

        case CharacterLifecycleState::EMERGENCY_RECOVERY:
            // Phục hồi sự cố: Khóa hành động bình thường, chỉ xử lý hồi sinh / đăng nhập
            return bot_action_mask::IDLE;

        default:
            return bot_action_mask::IDLE;
    }
}
```

### 5.2. Cơ Chế Khóa Chặn Trọng Tài Tại `BotBrain::Process` (Architectural Gate)

Trước khi thực hiện bất kỳ phép so sánh Priority nào giữa các đề xuất của handler:
```cpp
bool BotBrain::Process(const TelemetryPacket& packet, KMBoxNet& kmbox, uint64_t nowMs) {
    const uint32_t allowedMask = GetAllowedActionMask(m_currentLifecycleState);

    ActionProposal bestProposal{};
    IActionHandler* bestHandler = nullptr;

    for (auto* handler : m_handlers) {
        ActionProposal proposal = handler->Propose(packet, nowMs);
        if (proposal.priority == 0 || proposal.kind == BotActionKind::None) continue;

        // BẤT BIẾN INV-CHAR-FSM-04: Khóa chặn tại cổng!
        const uint32_t proposalBit = (1 << static_cast<uint16_t>(proposal.kind));
        if ((allowedMask & proposalBit) == 0) {
            // Đề xuất bị từ chối do không phù hợp với Macro State hiện tại!
            // Ví dụ: QuestNavigator đề xuất EXPLORE khi đang HIDEOUT_IDLE -> BỊ TRIỆT TIÊU 100%!
            continue;
        }

        if (proposal.priority > bestProposal.priority) {
            bestProposal = proposal;
            bestHandler = handler;
        }
    }

    if (bestHandler && bestProposal.priority > 0) {
        return bestHandler->Execute(bestProposal, packet, kmbox, nowMs);
    }
    return false;
}
```

$\implies$ **Kết quả kiến trúc đột phá**:  
Khi ở `HIDEOUT_IDLE`, `allowedMask` chỉ chứa `IDLE | FLASK`.  
Dù `QuestNavigator` có đề xuất `EXPLORE` (priority 1000) hay `UnstuckHandler` có đề xuất `UNSTUCK` (priority 8000), chúng đều **bị triệt tiêu ngay lập tức tại cổng lọc bitmask (0ms latency, O(1) CPU instructions)**!

---

## 6. Danh Mục Bất Biến Kiến Trúc (Architectural Invariants Matrix)

Mọi dòng mã trong đợt triển khai phải tuân thủ nghiêm ngặt 5 Bất biến Kiến trúc sau đây:

### 6.1. Bất Biến `INV-CHAR-FSM-01`: Zero-Movement Hideout Invariant (Cấm Di Chuyển Tuyệt Đối Tại Hideout Khi Nhàn Rỗi)
- **Nội dung**: Khi nhân vật ở trạng thái `HIDEOUT_IDLE`, nghiêm cấm tuyệt đối phát sinh bất kỳ tín hiệu di chuyển vật lý nào (phím WASD, click chuột trái di chuyển, micro-stepping) hoặc hành vi tuần tra tìm đường (`Explore` / `AutoPatrol`).
- **Ràng buộc mã nguồn**:
  - `GetAllowedActionMask(HIDEOUT_IDLE)` KHÔNG ĐƯỢC chứa bit `EXPLORE` hoặc `SWITCH_AREA`.
  - `QuestNavigator::Propose` khi phát hiện `isTown == true` bắt buộc phải trả về `{}` hoặc `BotActionKind::Idle` với hành động rỗng.
- **Hình phạt vi phạm**: Nếu phát hiện tọa độ $(X, Y)$ thay đổi $> 5.0\text{u}$ trong trạng thái `HIDEOUT_IDLE` mà không do tác động ngoại cảnh $\implies$ Kích hoạt `assert(false)` và ghi log vi phạm Invariant.

### 6.2. Bất Biến `INV-CHAR-FSM-02`: Unstuck Scope Isolation Invariant (Cô Lập Phạm Vi Hoạt Động Của Bộ Gỡ Kẹt)
- **Nội dung**: Bộ gỡ kẹt `UnstuckHandler` CHỈ ĐƯỢC PHÉP hoạt động trong trạng thái `MAP_FARMING_COMBAT` và `HIDEOUT_MAP_DEVICE_APPROACH` (với logic trượt tiếp tuyến nhẹ). Nghiêm cấm tuyệt đối kích hoạt lộn nhào né đòn Iframe Dodge Roll (`VK_SPACE`) hoặc phím mở Town Portal (`.`) khi nhân vật đang ở trong Hideout hoặc Làng (Town).
- **Ràng buộc mã nguồn**:
  - `UnstuckHandler::Propose` phải kiểm tra `packet.area.areaName` và `packet.area.areaCode`. Nếu là Town/Hideout $\implies$ Tự động vô hiệu hóa bộ đếm thời gian kẹt `m_lastMovementCheckMs` và không bao giờ chuyển sang `UnstuckReason::MovementStuck`.
  - `UnstuckHandler::Execute` phải có lệnh kiểm tra an toàn:
    `if (isTown && chosen.kind == BotActionKind::Unstuck) return false;`

### 6.3. Bất Biến `INV-CHAR-FSM-03`: Loading & Grace Period Invulnerability Invariant (Bảo Toàn Trạng Thái Ân Hạn Bất Tử)
- **Nội dung**: Khi nhân vật đang ở trạng thái `UNINITIALIZED_OR_LOADING` hoặc `MAP_LOADING_GRACE`, mọi thao tác input phím và chuột bị khóa cứng 100%. Hệ thống không được phép phá vỡ thời gian ân hạn Grace Period (Grace Buff từ server game) trước khi toàn bộ NavMesh địa hình và bộ đệm Telemetry RAM được đồng bộ hóa hoàn toàn và nhân vật sẵn sàng chiến đấu.
- **Ràng buộc mã nguồn**:
  - Khóa hardware input thông qua KMBox interlock.
  - Chỉ thoát khỏi `MAP_LOADING_GRACE` khi: (1) NavMesh terrain nạp xong, (2) Quét quái vật xung quanh hoàn tất, HOẶC (3) Nhân vật bị mất máu do quái vật đánh trúng.

### 6.4. Bất Biến `INV-CHAR-FSM-04`: Hierarchical Priority Supremacy Invariant (Thứ Bậc Tối Thượng Của FSM Vòng Đời)
- **Nội dung**: Máy trạng thái vòng đời `BotLifecycleFSM` là cơ quan giám sát tối cao (Top-Level Supervisor). Trọng tài ưu tiên `BotBrain Priority Arbiter` chỉ được quyền điều phối các hành động vi mô (Micro-Actions) nằm trong tập hành động hợp lệ (`AllowedActionMask`) được cấp phép bởi Macro State hiện tại.
- **Ràng buộc mã nguồn**:
  - CẤM mọi handler tự ý vượt cấp (bypass) mặt nạ `AllowedActionMask`.
  - Không có bất kỳ ngoại lệ `|| true` hoặc bỏ qua kiểm tra bitmask nào được phép tồn tại trong mã nguồn.

### 6.5. Bất Biến `INV-CHAR-FSM-05`: Deterministic State Transition & Watchdog Invariant (Chuyển Trạng Thái Xác Định & Chó Săn Giám Sát)
- **Nội dung**: Mọi chuyển dịch trạng thái FSM phải dựa trên bằng chứng dữ liệu Telemetry RAM thực tế hoặc sự kiện xác định từ Log/IPC, nghiêm cấm chuyển trạng thái ngẫu nhiên hoặc phỏng đoán. Mỗi trạng thái bắt buộc phải có một bộ đếm thời gian giám sát cứng (Watchdog Timer). Nếu một trạng thái kéo dài vượt quá ngưỡng timeout quy định mà không đạt điều kiện chuyển tiếp, hệ thống bắt buộc kích hoạt `EMERGENCY_RECOVERY` thay vì treo vô tận.
- **Ràng buộc mã nguồn**:
  - Kiểm tra `nowMs - m_stateEntryTimestampMs > GetStateTimeoutMs(m_currentState)`.
  - Khi timeout: Ghi log cảnh báo `CoreLog("[FSM Watchdog] State " + StateToString(...) + " TIMEOUT! Forcing EMERGENCY_RECOVERY.")` và chuyển ngay sang `EMERGENCY_RECOVERY`.

---

## 7. Hợp Đồng Nhị Phân & Tích Hợp Hai Tầng (Binary Contract & Tier 1/2 IPC)

### 7.1. Mở Rộng Cấu Trúc Dữ Liệu Bộ Nhớ Chia Sẻ (Shared Memory Protocol)

Cập nhật tệp [`src/core/common/protocol.hpp`](../../src/core/common/protocol.hpp):

#### A. Bổ sung `CharacterLifecycleState` vào `PlayerTelemetryData`
Giúp Python Companion HUD (Tier 2) có thể đọc trạng thái FSM hiện tại với độ trễ 0ms qua Seqlock 39KB:

```cpp
// Thêm vào PlayerTelemetryData trong protocol.hpp
struct PlayerTelemetryData {
    // ... các trường hiện có (currentHP, maxHP, posX, posY, posZ...)
    
    uint8_t lifecycleState;        // Giá trị enum CharacterLifecycleState (0 - 10)
    uint8_t lifecycleFlags;        // Bit 0: IsInGracePeriod, Bit 1: IsStashOpen, Bit 2: IsMapDeviceOpen
    uint16_t stateDurationSeconds; // Thời gian đã ở trong trạng thái hiện tại (giây)
};
```

#### B. Bổ sung OpCodes Điều Khiển Macro Trong `CommandPacket`

```cpp
enum class MacroOpCode : uint32_t {
    // ... các OpCodes hiện có (0..9, 95..99)
    SET_LIFECYCLE_STATE = 10,     // Ép chuyển trạng thái FSM thủ công (Debug/Override)
    START_FARM_LOOP     = 11,     // Khởi động vòng lặp farm tự động (tương đương phím F8)
    PAUSE_FARM_LOOP     = 12,     // Tạm dừng vòng lặp farm (về HIDEOUT_IDLE)
    FORCE_MAP_DEVICE    = 13      // Kích hoạt ngay chu trình Map Device từ UI
};
```

---

### 7.2. Tích Hợp Tầng Python Companion (Tier 2 Cold Path)

1. **Hiển Thị Trực Quan Trên Control Center GUI**:
   - Module `src/assistant_tool/control_center.py` và Companion Overlay hiển thị Badge trạng thái FSM với màu sắc trực quan:
     * `HIDEOUT_IDLE`: Xanh dương nhạt (`#38bdf8`) — "💤 Hideout Nhàn Rỗi (Đứng yên)"
     * `HIDEOUT_STASHING`: Vàng cam (`#f59e0b`) — "📦 Đang Cất Hòm Đồ"
     * `HIDEOUT_MAP_DEVICE_*`: Tím (`#a855f7`) — "🗺️ Đang Nạp & Bật Map Device"
     * `MAP_FARMING_COMBAT`: Xanh lá cây (`#22c55e`) — "⚔️ Đang Chiến Đấu & Farm Map"
     * `EMERGENCY_RECOVERY`: Đỏ thắm (`#ef4444`) — "⚠️ Đang Tự Phục Hồi Sự Cố"
2. **Đồng Bộ Phím Tắt F8 Hai Chiều**:
   - Khi người dùng nhấn F8 trên bàn phím hoặc click nút "START BOT" trên giao diện:
     Python gửi gói lệnh `CommandPacket { opCode: START_FARM_LOOP }` qua SPSC Ring Buffer.
   - C++ Core nhận lệnh, kiểm tra khu vực hiện tại:
     * Nếu đang ở Hideout $\implies$ Chuyển FSM sang `HIDEOUT_IDLE` và bắt đầu đánh giá túi đồ Row 0.
     * Nếu đang ở trong Map $\implies$ Chuyển FSM sang `MAP_FARMING_COMBAT`.

---

## 8. Lộ Trình Triển Khai Thực Thi (Implementation Roadmap)

Tuân thủ nghiêm ngặt quy trình phát triển AutoPOE2:

### Giai Đoạn 1: Tầng C++ Core Engine (Tier 1 Hot Path)
1. **Tạo mới lớp điều phối vòng đời**: `src/core/brain/character_lifecycle_manager.hpp` và `.cpp`.
   - Cài đặt 11 trạng thái vĩ mô và bộ đếm Watchdog Timer.
   - Cài đặt hàm `GetAllowedActionMask(state)`.
2. **Tái cấu trúc `BotBrain`**:
   - Tích hợp con trỏ `CharacterLifecycleManager* m_lifecycleMgr`.
   - Áp dụng bộ lọc `allowedMask` tại `BotBrain::Process`.
3. **Hiệu chỉnh `QuestNavigator` & `UnstuckHandler`**:
   - `QuestNavigator::Propose`: Khi `isTown == true`, trả về `{}` (không đề xuất di chuyển khi nhàn rỗi).
   - `UnstuckHandler::Propose`: Bỏ qua kiểm tra kẹt khi ở Hideout/Town.

### Giai Đoạn 2: Tầng Python Companion (Tier 2 Cold Path)
1. **Cập nhật Struct Telemetry Python**:
   - Cập nhật ctypes wrapper trong `src/assistant_tool/` đọc trường `lifecycleState`.
2. **Cập nhật GUI & Telemetry Overlay**:
   - Hiển thị nhãn trạng thái FSM trực quan thời gian thực.

---

## 9. Kế Hoạch Kiểm Thử & Nghiệm Thu Thực Nghiệm (Empirical Verification Plan)

Tuân thủ nghiêm ngặt **Rule 9 (Empirical Definition of Done)** và **Rule 11 (Automated Mock Harness)**:

### 9.1. Bài Kiểm Thử C++ Mock Harness Tự Động (`AutoPOE2_Tests.exe`)
1. **Test Case 1: `TEST_FSM_Hideout_Idle_Zero_Movement`**:
   - Nạp Telemetry giả lập nhân vật tại Hideout (`areaName = "Shoreline Hideout"`).
   - Kích hoạt FSM sang `HIDEOUT_IDLE`.
   - Chạy 1200 ticks (tương đương 10 giây ở 120Hz).
   - **Xác nhận**:
     * `BotBrain::LastChosen().kind == BotActionKind::Idle` hoặc `None`.
     * Zero lệnh WASD gửi sang KMBox.
     * Zero phím Spacebar (Dodge Roll) được kích hoạt.
     * `UnstuckHandler::IsStuck() == false`.
2. **Test Case 2: `TEST_FSM_Allowed_Action_Mask_Filtering`**:
   - Ép FSM vào `HIDEOUT_IDLE`.
   - Mock cho `QuestNavigator` đề xuất `BotActionKind::Explore` với priority 4000.
   - Mock cho `UnstuckHandler` đề xuất `BotActionKind::Unstuck` với priority 8000.
   - **Xác nhận**: `BotBrain::Process` từ chối cả 2 đề xuất trên vì bị chặn bởi `AllowedActionMask`, trả về `false`.
3. **Test Case 3: `TEST_FSM_Full_Cycle_Transitions`**:
   - Mô phỏng chu trình chuyển trạng thái tuần tự:
     `HIDEOUT_IDLE` $\rightarrow$ `HIDEOUT_PREPARE_MAP` $\rightarrow$ `HIDEOUT_MAP_DEVICE_APPROACH` $\rightarrow$ `HIDEOUT_MAP_DEVICE_ACTIVATE` $\rightarrow$ `HIDEOUT_ENTER_PORTAL` $\rightarrow$ `UNINITIALIZED_OR_LOADING` $\rightarrow$ `MAP_LOADING_GRACE` $\rightarrow$ `MAP_FARMING_COMBAT` $\rightarrow$ `MAP_COMPLETED_PORTAL_OUT` $\rightarrow$ `HIDEOUT_IDLE`.
   - **Xác nhận**: 100% bước chuyển trạng thái diễn ra chính xác theo điều kiện kích hoạt.
4. **Test Case 4: `TEST_FSM_Watchdog_Timeout_Recovery`**:
   - Giữ FSM tại `HIDEOUT_MAP_DEVICE_APPROACH` quá 15.000ms mà không cho tới đích.
   - **Xác nhận**: Watchdog kích hoạt, FSM tự động nhảy sang `EMERGENCY_RECOVERY`.

---

## 10. Kết Luận

Tài liệu đặc tả này chấm dứt hoàn toàn kỷ nguyên "vá chắp vá" các điều kiện `if/else` phân mảnh giữa các handler trong AutoPOE2. Bằng cách thiết lập **Máy Trạng Thái Quản Lý Vòng Đời Nhân Vật Chuẩn Mực (`BotLifecycleFSM`)** kết hợp cùng **Mặt Nạ Phân Quyền Hành Động (`AllowedActionMask`)**, hệ thống đạt được:
1. **Triệt tiêu 100% hiện tượng nhân vật chạy đâm đầu vào tường và lộn nhào vô lý tại Hideout khi bật F8.**
2. **Thiết lập quyền lực kiểm soát rõ ràng giữa Macro State (Vòng đời) và Micro Actions (Phản xạ/Chiến đấu).**
3. **Bảo đảm độ tin cậy, tính xác định (Determinism) và khả năng tự phục hồi (Resilience) chuẩn mực cấp thương mại năm 2026.**
