# Master Architectural Survey & QA Investigation Report
## Character Stat Aggregator: Persistence & Test Infrastructure

- **Target System**: FreeExile Server Backend — Character Stat Aggregator, Formula Persistence, and Engine Loop Integration
- **Investigator**: Teamwork Explorer (`explorer_survey_3`)
- **Authoritative Reference**: `ORIGINAL_REQUEST.md` (Header `## 2026-10-04T09:01:16Z`)
- **Date**: 2026-10-04

---

## 1. Executive Summary

This investigation surveys the database persistence patterns, formula audit schema, testing infrastructure, and engineering hygiene standards in FreeExile to guide the implementation of the **Character Stat Aggregator** system (`CharacterStatAggregator`).

The aggregator combines base character attributes, equipped item affixes from `inventory_service.py`, and passive constellation bonuses from `meridian_service.py` under Path of Exile-grade modifier math (Flat additions, Increased/Reduced percentages, More/Less multipliers, Tag-based filters, and Conditional triggers). Furthermore, every stat calculation is decomposed into a serialized JSON/AST structure stored in SQLite for zero-trust auditing and verification.

### Core Discoveries at a Glance
| Investigation Area | Key Finding | Architectural Implication |
| :--- | :--- | :--- |
| **SQLite DB Patterns** | 7 dedicated databases reside in `data/` (`game_design_matrix.db`, `map_styles.db`, `agent_delegations.db`, etc.). Context managers manage connections with WAL journal mode, `PRAGMA synchronous = NORMAL`, and `foreign_keys = ON`. | Formula persistence should reside in `data/character_stat_formulas.db` (or `:memory:` in tests) using an atomic repository pattern. |
| **Formula Persistence Schema** | Requires auditing exact formula execution paths per player calculation. | Table `character_stat_calculations` with columns `(id, player_id, calculation_id, timestamp, formula_ast_json, final_stats_json, context_tags_json, created_at)`. |
| **Formula AST Structure** | Tree structure representing mathematical expressions for each stat (`Constant`, `Sum`, `ScaleFactor`, `Product`, `BinaryOp`). | Every contributing modifier records its `source`, `modifier_type`, `value`, `tags`, and condition evaluation state. |
| **Test Infrastructure** | Fast `pytest`/`unittest` suite (`tests/unit/`). Tests mock services (`InventoryService`, `MeridianService`, `QuestEngine`) and use `tempfile.TemporaryDirectory` for DBs. | Dedicated test suite `tests/unit/test_character_stat_aggregator.py` will test calculation math, SQLite persistence, and engine loop wiring. |
| **Hygiene & Blast Radius** | `tools/lint/check_code_and_doc_hygiene.py` enforces <=350 soft cap / <=500 hard cap. `server_engine_loop.py` is CRITICAL with 7 dependents. | Implementation files must be modularized into `stat_types.py`, `formula_persistence.py`, and `stat_aggregator.py`. Editing `server_engine_loop.py` requires `--ack`. |

---

## 2. SQLite Database Usage in FreeExile

### 2.1. Repository Layout & Existing Databases
All SQLite databases in FreeExile are centrally placed in the top-level `data/` directory:
- `data/game_design_matrix.db` (241 KB) — 17 relational tables for Acts, Zones, Monsters, Loot allocation, Quests, and cross-relationships.
- `data/map_styles.db` (290 KB) — Procedural biome generation styles, tile definitions, and lighting settings.
- `data/agent_delegations.db` (24 KB) — Multi-LLM Agent Orb offline hunting state, delegations, and harvest logs.
- `data/trade_ledger.db` (49 KB) — Two-phase commit ledger for barter trading and anti-duplication escrow.
- `data/feedback_store.db` (24 KB) — Player feedback and rating analytics.
- `data/martial_database.db` (53 KB) — Martial matrix and skill databases.
- `data/social_store.db` (20 KB) — Guilds, parties, and chat relationships.

### 2.2. Connection Management & Concurrency
The project utilizes several canonical patterns for SQLite connection handling:

1. **Context Manager Pattern (`GameDesignMatrixService` in `server/world/game_design_matrix_service.py:103-120`)**:
   ```python
   @contextmanager
   def _get_connection(self):
       if self._memory_conn is not None:
           yield self._memory_conn
           self._memory_conn.commit()
       else:
           conn = sqlite3.connect(self.db_path)
           conn.row_factory = sqlite3.Row
           conn.executescript(SQL_PRAGMA_SETUP)
           try:
               yield conn
               conn.commit()
           except Exception:
               conn.rollback()
               raise
           finally:
               conn.close()
   ```

2. **In-Memory Lifespan Handling (`:memory:`)**:
   In SQLite, an in-memory database (`:memory:`) is discarded the moment its connection closes. Services support unit testing by maintaining a persistent connection `self._memory_conn = sqlite3.connect(":memory:")` when `db_path == ":memory:"`.

3. **High-Concurrency SQLite PRAGMAs**:
   Defined in `server/world/game_design_matrix_schema.py:8-12`:
   ```sql
   PRAGMA foreign_keys = ON;
   PRAGMA journal_mode = WAL;
   PRAGMA synchronous = NORMAL;
   ```
   For multi-threaded services (e.g. `agent_orb_service.py`, `two_phase_commit.py`), `check_same_thread=False` and `timeout=10.0` or `timeout=30.0` are configured.

### 2.3. Migration & Initialization Conventions
- **Idempotent DDL**: Tables are created using `CREATE TABLE IF NOT EXISTS` and indices using `CREATE INDEX IF NOT EXISTS`.
- **Schema Version Inspection**: `_check_and_migrate_schema(conn)` checks `PRAGMA table_info(table_name)` to determine if existing tables match the required column count, or uses `ALTER TABLE ... ADD COLUMN ...` wrapped in try/except blocks (as seen in `server/world/meridian_service.py:86-88`).

### 2.4. Recommended Placement for Formula Persistence
- **Database File**: `data/character_stat_formulas.db`
- **Class**: `FormulaPersistenceRepository` (or `StatFormulaDatabase`) in `server/stats/formula_persistence.py`
- **Configuration**:
  - Default `db_path`: `os.path.abspath(os.path.join(PROJECT_ROOT, "data", "character_stat_formulas.db"))`.
  - Pass `db_path=":memory:"` for zero-disk, ultra-fast unit testing.
  - Automatically invoke `os.makedirs(os.path.dirname(db_path), exist_ok=True)` on disk initialization.

---

## 3. Schema & Format for Formula Persistence (R2 Audit Specification)

### 3.1. SQLite Relational Schema
```sql
CREATE TABLE IF NOT EXISTS character_stat_calculations (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    player_id TEXT NOT NULL,
    calculation_id TEXT NOT NULL UNIQUE,  -- UUIDv4 or deterministic session hash
    timestamp REAL NOT NULL,              -- Epoch timestamp (time.time())
    formula_ast_json TEXT NOT NULL,       -- Serialized JSON AST tree per stat
    final_stats_json TEXT NOT NULL,       -- Serialized dictionary of final evaluated values
    context_tags_json TEXT NOT NULL,      -- Active tags and boolean condition flags
    created_at TEXT NOT NULL DEFAULT (DATETIME('now'))
);

CREATE INDEX IF NOT EXISTS idx_stat_calc_player ON character_stat_calculations(player_id);
CREATE INDEX IF NOT EXISTS idx_stat_calc_timestamp ON character_stat_calculations(timestamp);
```

### 3.2. AST Serialization Model for Stat Formulas
To ensure complete transparency and auditability, each calculated stat generates an AST node hierarchy expressing:
$$\text{FinalStat} = (\text{Base} + \sum \text{Flat}) \times (1.0 + \frac{\sum \text{Increased} - \sum \text{Reduced}}{100.0}) \times \prod (1.0 + \frac{\text{More}_i}{100.0}) \times \prod (1.0 - \frac{\text{Less}_j}{100.0})$$

#### Node Types in the AST
1. `Constant`: Fixed numerical value (e.g., base attack damage or base HP).
2. `Sum`: Summation of flat modifiers.
3. `ScaleFactor`: Percentage scale factor `(1.0 + sum(increased - reduced) / 100.0)`.
4. `Product`: Independent multiplicative factor `prod(1.0 + more / 100.0)`.
5. `BinaryOp`: Operator (`ADD`, `MUL`) connecting components.
6. `ModifierContribution`: Details of an individual modifier (source, value, tags, condition).

#### Serialized `formula_ast_json` Structure (Sample)
```json
{
  "max_hp": {
    "stat_name": "max_hp",
    "final_value": 1416.8,
    "ast_type": "BinaryOp",
    "operator": "MUL",
    "left": {
      "ast_type": "BinaryOp",
      "operator": "ADD",
      "left": {
        "ast_type": "Constant",
        "name": "base",
        "value": 1000.0,
        "source": "character_base"
      },
      "right": {
        "ast_type": "Sum",
        "name": "flat_modifiers",
        "total": 120.0,
        "children": [
          {
            "ast_type": "ModifierContribution",
            "source": "meridian:m_c1",
            "modifier_type": "FLAT",
            "value": 40.0,
            "tags": ["life"],
            "condition": null,
            "condition_met": true
          },
          {
            "ast_type": "ModifierContribution",
            "source": "item:HELMET:affix_0",
            "modifier_type": "FLAT",
            "value": 80.0,
            "tags": ["life"],
            "condition": null,
            "condition_met": true
          }
        ]
      }
    },
    "right": {
      "ast_type": "BinaryOp",
      "operator": "MUL",
      "left": {
        "ast_type": "ScaleFactor",
        "name": "increased_reduced_multiplier",
        "percentage_sum": 15.0,
        "multiplier": 1.15,
        "children": [
          {
            "ast_type": "ModifierContribution",
            "source": "meridian:m_n1",
            "modifier_type": "INCREASED",
            "value": 15.0,
            "tags": ["life"],
            "condition": null,
            "condition_met": true
          }
        ]
      },
      "right": {
        "ast_type": "Product",
        "name": "more_less_multiplier",
        "multiplier": 1.10,
        "children": [
          {
            "ast_type": "ModifierContribution",
            "source": "passive:blood_essence",
            "modifier_type": "MORE",
            "value": 10.0,
            "tags": ["life"],
            "condition": "on_low_life",
            "condition_met": true
          }
        ]
      }
    }
  },
  "base_attack": {
    "stat_name": "base_attack",
    "final_value": 137.5,
    "ast_type": "BinaryOp",
    "operator": "MUL",
    "left": {
      "ast_type": "BinaryOp",
      "operator": "ADD",
      "left": {
        "ast_type": "Constant",
        "name": "base",
        "value": 50.0,
        "source": "character_base"
      },
      "right": {
        "ast_type": "Sum",
        "name": "flat_modifiers",
        "total": 60.0,
        "children": [
          {
            "ast_type": "ModifierContribution",
            "source": "item:MAIN_HAND:affix_phys_dmg",
            "modifier_type": "FLAT",
            "value": 50.0,
            "tags": ["physical", "attack"],
            "condition": null,
            "condition_met": true
          },
          {
            "ast_type": "ModifierContribution",
            "source": "meridian:m_c2",
            "modifier_type": "FLAT",
            "value": 10.0,
            "tags": ["physical"],
            "condition": null,
            "condition_met": true
          }
        ]
      }
    },
    "right": {
      "ast_type": "ScaleFactor",
      "name": "increased_multiplier",
      "percentage_sum": 25.0,
      "multiplier": 1.25,
      "children": [
        {
          "ast_type": "ModifierContribution",
          "source": "item:RING_1:affix_phys_pct",
          "modifier_type": "INCREASED",
          "value": 25.0,
          "tags": ["physical"],
          "condition": null,
          "condition_met": true
        }
      ]
    }
  }
}
```

### 3.3. Serialized `final_stats_json` Structure
```json
{
  "max_hp": 1416.8,
  "current_hp": 1416.8,
  "base_attack": 137.5,
  "crit_chance": 0.12,
  "crit_multiplier": 1.85,
  "armor": 350,
  "evasion": 0.15,
  "resist_kim": 25.0,
  "resist_moc": 10.0,
  "resist_thuy": 10.0,
  "resist_hoa": 45.0,
  "resist_tho": 10.0
}
```

### 3.4. Serialized `context_tags_json` Structure
```json
{
  "active_tags": ["physical", "attack", "melee", "life", "defense"],
  "conditions": {
    "on_low_life": true,
    "on_full_life": false,
    "is_moving": false,
    "is_dual_wielding": true
  }
}
```

---

## 4. Stat Aggregator Core Architecture (R1 & R3)

### 4.1. Stat Modifier Type Specifications
Following Elite Standards 2026, all data objects use `@dataclass(slots=True, frozen=True)`:

```python
class ModifierType(str, Enum):
    FLAT = "FLAT"           # Added to base: +X
    INCREASED = "INCREASED" # Additive percentage: +X%
    REDUCED = "REDUCED"     # Additive percentage reduction: -X%
    MORE = "MORE"           # Multiplicative percentage: * (1 + X/100)
    LESS = "LESS"           # Multiplicative percentage: * (1 - X/100)

@dataclass(slots=True, frozen=True)
class StatModifier:
    stat_key: str
    mod_type: ModifierType
    value: float
    source: str
    tags: Tuple[str, ...] = ()
    condition_key: Optional[str] = None
    expected_condition_val: bool = True

@dataclass(slots=True, frozen=True)
class CalculationContext:
    active_tags: Tuple[str, ...] = ()
    conditions: Dict[str, bool] = field(default_factory=dict)
```

### 4.2. Extraction from Upstream Services
The aggregator integrates three primary sources:

1. **Character Base Stats**:
   - `max_hp = 1000.0`, `base_attack = 50.0`, `crit_chance = 0.05`, `crit_multiplier = 1.50`, `armor = 0`, `evasion = 0.0`, resistances = 0.0.
2. **Equipped Items (`inventory_service.py`)**:
   - Fetches character inventory: `inv = inventory_service.get_character_inventory(account_id, character_id)`.
   - Iterates `inv.equipment.items()` (slots: `MAIN_HAND`, `OFF_HAND`, `HELMET`, `BODY_ARMOR`, `GLOVES`, `BOOTS`, `AMULET`, `RING_1`, `RING_2`, `BELT`).
   - For each item, inspects `item.affixes`:
     - `stat_key="phys_dmg"`, `current_val=40` -> `StatModifier(stat_key="base_attack", mod_type=ModifierType.FLAT, value=40, source="item:MAIN_HAND")`.
     - `stat_key="max_hp"`, `current_val=80` -> `StatModifier(stat_key="max_hp", mod_type=ModifierType.FLAT, value=80, source="item:HELMET")`.
     - `stat_key="crit_rate"`, `current_val=8` -> `StatModifier(stat_key="crit_chance", mod_type=ModifierType.FLAT, value=0.08, source="item:RING_1")`.
3. **Passive Constellation (`meridian_service.py`)**:
   - Calls `stats = meridian_service.compute_total_stats(player_id)`.
   - Yields `MeridianStatBonus`:
     - `hp`: flat `max_hp` bonus.
     - `dps`: flat attack damage bonus.
     - `dps_mult`: percentage `INCREASED` attack damage bonus (`value = stats.dps_mult * 100.0`).
     - `crit_rate`: flat crit chance bonus.
     - `crit_dmg`: flat crit multiplier bonus.
     - `armor`: flat armor bonus.
     - `evasion`: flat evasion bonus.
     - `resist`: flat elemental resistances bonus.

### 4.3. Mathematical Aggregation Algorithm
For a given stat $S$:
1. **Filter Eligible Modifiers**:
   - Matches stat key: `m.stat_key == S`.
   - Matches tags: if `m.tags` is non-empty, all tags in `m.tags` must exist in `context.active_tags`.
   - Matches conditions: if `m.condition_key` is set, `context.conditions.get(m.condition_key) == m.expected_condition_val`.
2. **Compute Flat Component**:
   $$\text{FlatTotal} = \text{Base} + \sum_{m \in \text{EligibleFlat}} m.\text{value}$$
3. **Compute Increased / Reduced Multiplier**:
   $$\text{IncSum} = \sum_{m \in \text{EligibleIncreased}} m.\text{value} - \sum_{m \in \text{EligibleReduced}} m.\text{value}$$
   $$\text{ScaleFactor} = \max(0.0, 1.0 + \frac{\text{IncSum}}{100.0})$$
4. **Compute More / Less Multipliers**:
   $$\text{MoreFactor} = \prod_{m \in \text{EligibleMore}} (1.0 + \frac{m.\text{value}}{100.0}) \times \prod_{m \in \text{EligibleLess}} (1.0 - \frac{m.\text{value}}{100.0})$$
5. **Compute Final Stat**:
   $$\text{FinalStat} = \text{FlatTotal} \times \text{ScaleFactor} \times \text{MoreFactor}$$
6. **Construct AST Tree**:
   Assemble `BinaryOp`, `Sum`, `ScaleFactor`, `Product`, and record all evaluated and skipped modifiers into the AST.

### 4.4. Server Engine Loop Integration (`server_engine_loop.py:86-114`)
In `ServerEngineLoop.register_player`:
```python
def register_player(
    self,
    entity_id: int,
    initial_x: float,
    initial_y: float,
    initial_z: float = 0.0,
    element: FiveElements = FiveElements.KIM,
    move_speed: float = 6.0,
    max_hp: float = 1000.0,
    player_id: Optional[str] = None,
    account_id: Optional[str] = None,
    aggregated_stats: Optional[Dict[str, float]] = None,
) -> None:
    ...
```
When `aggregated_stats` is provided (or when calculated via an injected `stat_aggregator`):
```python
    calc_hp = aggregated_stats.get("max_hp", max_hp) if aggregated_stats else max_hp
    calc_atk = aggregated_stats.get("base_attack", 50.0) if aggregated_stats else 50.0
    calc_crit = aggregated_stats.get("crit_chance", 0.05) if aggregated_stats else 0.05
    calc_crit_mult = aggregated_stats.get("crit_multiplier", 1.5) if aggregated_stats else 1.5

    combat_actor = CombatActor(
        actor_id=entity_id,
        name=f"Player_{entity_id}",
        element=element,
        current_hp=calc_hp,
        max_hp=calc_hp,
        base_attack=calc_atk,  # Aggregated attack damage instead of default 50.0
        crit_chance=calc_crit,
        crit_multiplier=calc_crit_mult,
        is_player=True,
        player_id=player_id or f"player_{entity_id}"
    )
    self.combat_engine.register_actor(combat_actor)
```
- **Backward Compatibility**: If no `aggregated_stats` or `stat_aggregator` is supplied, `base_attack` defaults to `50.0`, preserving zero breakage across existing unit tests (such as `test_isometric_engine_loop.py`).

---

## 5. Existing Testing Infrastructure & Fixtures

### 5.1. Test Suite Architecture
- Runner: `pytest 9.1.1` under Python 3.11.9.
- Directory Hierarchy:
  - `tests/unit/` (134 test files): Fast, self-contained unit tests.
  - `tests/integration/`: Service orchestration and gateway flows.
  - `tests/security_fuzzing/`: Penetration testing and adversarial checks.
  - `tests/e2e/`: Full simulation end-to-end loops.

### 5.2. Mocking & Fixture Patterns Observed
1. **Isolated SQLite Database per Test**:
   Using `tempfile.TemporaryDirectory()` in `setUp()` and cleanup in `tearDown()`:
   ```python
   def setUp(self) -> None:
       self.temp_dir = tempfile.TemporaryDirectory()
       self.db_path = os.path.join(self.temp_dir.name, "test_formulas.db")
   def tearDown(self) -> None:
       self.temp_dir.cleanup()
   ```
2. **Service Setup Mocks**:
   - `MegaShopService`: Instantiated directly without external dependencies (`shop = MegaShopService()`).
   - `InventoryService`: Instantiated as `InventoryService(shop_service=shop)`.
   - `MeridianService`: Instantiated as `MeridianService(db_path=self.db_path)`.
   - `ServerEngineLoop`: Instantiated as `ServerEngineLoop(cell_size=64.0)`.

### 5.3. Recommended Dedicated Test Suite
A dedicated test suite should be placed at `tests/unit/test_character_stat_aggregator.py`, covering:
1. `test_flat_and_increased_modifiers_math()`: Asserts exact mathematical calculations:
   - Base 50, Flat +50, Increased +20% -> $(50 + 50) \times 1.20 = 120.0$.
2. `test_more_and_less_multipliers_compound()`:
   - Base 100, Flat 0, More +10%, More +20% -> $100 \times 1.10 \times 1.20 = 132.0$.
3. `test_tag_based_filtering()`:
   - "increased fire damage" only affects attacks with `"fire"` tag; physical attacks ignore it.
4. `test_conditional_modifiers_on_low_life()`:
   - Modifier applies only when `on_low_life=True`; skipped when `on_low_life=False`.
5. `test_inventory_and_meridian_ingestion()`:
   - Equips an item with physical damage affix; unlocks meridian node; confirms both aggregate into final stats.
6. `test_sqlite_formula_persistence_and_audit()`:
   - Confirms row inserted into `character_stat_calculations`; parses `formula_ast_json` and asserts valid AST JSON hierarchy.
7. `test_server_engine_loop_registration_with_aggregated_stats()`:
   - Invokes `engine.register_player(...)` with aggregated stats; verifies `actor.base_attack != 50.0` (asserts calculated value e.g. `125.0`).

---

## 6. Code Hygiene, Line Limits & Blast Radius Analysis

### 6.1. Line Limit Policies (`tools/lint/check_code_and_doc_hygiene.py`)
| File Category | Soft Cap | Hard Cap | Enforcement Action |
| :--- | :--- | :--- | :--- |
| **Logic Code (.py, .ts, .js)** | 350 lines | 500 lines | >350 generates Warning; >500 causes exit code 1 (failure) |
| **Data Catalog (*_catalog.py)** | 700 lines | 1000 lines | Dedicated catalog cap |
| **Documentation (.md)** | 400 lines | 600 lines | Strictly enforced in Diátaxis docs |
| **Functions / Methods** | - | 50 lines | AST check; functions must be <= 50 lines |

### 6.2. Recommended Module Decomposition
To stay comfortably below the 350 lines Soft Cap:
1. `server/stats/stat_types.py` (~120 lines):
   - Enums (`ModifierType`, `StatKey`), DTOs (`StatModifier`, `CalculationContext`), AST node dataclasses (`StatASTNode`, `ModifierContribution`), and result structures (`AggregatedStatsResult`). All frozen slots dataclasses.
2. `server/stats/formula_persistence.py` (~180 lines):
   - SQLite table initialization (`character_stat_calculations`), WAL pragma setup, CRUD operations (`save_calculation`, `get_latest_calculation`, `get_history`), and JSON AST serialization/deserialization.
3. `server/stats/stat_aggregator.py` (~250 lines):
   - Business logic for modifier extraction from inventory items and meridian passives, mathematical aggregation loop, AST tree construction, and integration with `CombatActor`.

### 6.3. Blast Radius Impact on `server/world/server_engine_loop.py`
Running `python tools/analysis/blast_radius.py --target server/world/server_engine_loop.py` outputs:
- **Risk Level**: `CRITICAL`
- **Dependent Files (7)**:
  - `server/agent/agent_decision_core.py`
  - `server/world/agent_orb_service.py`
  - `tests/security_fuzzing/test_agent_security_fuzzing.py`
  - `tests/unit/test_agent_decision_core.py`
  - `tests/unit/test_agent_orb_hmac.py`
  - `tests/unit/test_agent_orb_service.py`
  - `tests/unit/test_isometric_engine_loop.py`
- **Native Impact Guard Requirement**:
  Before any code edit to `server/world/server_engine_loop.py`, the builder agent MUST run:
  ```bash
  python tools/analysis/blast_radius.py --target server/world/server_engine_loop.py --ack
  ```
  to unlock the 30-minute editing window.

---

## 7. Implementation Roadmap & Quality Checklist

### Phase 1: Models & Persistence Layer
- [ ] Create `server/stats/stat_types.py` with immutable, slots dataclasses for modifiers, AST nodes, and contexts.
- [ ] Create `server/stats/formula_persistence.py` with SQLite DDL, WAL configuration, and AST JSON persistence.
- [ ] Verify clean execution with `python -m unittest` or `pytest`.

### Phase 2: Core Aggregator Engine
- [ ] Create `server/stats/stat_aggregator.py` implementing `CharacterStatAggregator`.
- [ ] Implement mathematical pipeline: Base + Flat additions -> Increased/Reduced factor -> More/Less product.
- [ ] Implement Tag-based filters and Conditional evaluation.
- [ ] Implement item affix reader from `InventoryService` and passives from `MeridianService`.
- [ ] Wire formula persistence: save calculation AST and final stats to SQLite.

### Phase 3: Server Engine Loop Integration & Ack
- [ ] Execute `python tools/analysis/blast_radius.py --target server/world/server_engine_loop.py --ack`.
- [ ] Update `server/world/server_engine_loop.py` in `register_player` to instantiate `CombatActor` with aggregated stats.

### Phase 4: Test Suite & Quality Gates
- [ ] Create `tests/unit/test_character_stat_aggregator.py` covering all 7 test scenarios.
- [ ] Run pytest: `pytest tests/unit/test_character_stat_aggregator.py tests/unit/test_isometric_engine_loop.py`.
- [ ] Run hygiene gate: `python tools/lint/check_code_and_doc_hygiene.py --strict`.

---
*Report compiled by Teamwork Explorer (`explorer_survey_3`).*
