# HOTFIX2 — REASONING EXCEPTION EVIDENCIA (§0B Alex)

Registro de excepciones REALES reproducidas manualmente en GUI Digital Optimus (PID 2256, Scheduled Task `DigitalOptimus_UserAgent_V1_Intel`).

## 14 CAMPOS OBLIGATORIOS

---

### TIMESTAMP
- **Primera repetición (mensaje PREGUNTA 1, 2 veces)**: `2026-09-20T17:50:26Z` y `2026-09-20T17:50:37Z` (UTC).
- **Tercera repetición (mensaje PREGUNTA 1, 3ª vez)**: `2026-09-20T17:50:43Z`.
- **Cuarta + última repetición (mensaje "muestra lo que esta registrado")**: `2026-09-20T17:51:19.012935Z` (UTC; capturado en `data/__last_ua_error.json` — timestamp local Alex ~13:51 = UTC-4).
- **Fuente**: `logs/optimus_runtime_pid2256.log` líneas 25-140. Seis (6) repeticiones IDÉNTICAS del traceback en 93 segundos.

### PID
- **Runtime User Agent actual vivo**: `PID = 2256` (reiniciado a las 13:07:29 local por hotfix anterior restart Scheduled Task).
- **Scheduled Task asociado**: `DigitalOptimus_UserAgent_V1_Intel` → `pythonw.exe -B runtime_v1/optimus_user_agent.py` WD=`runtime_v1`.
- **SINGLE_INSTANCE**: 1 UA vivo. No hay PID conflictivos.

### BUILD_ID
- Baseline frozen strict: hash baseline `.dev_f8_f15` 541 files INTACTA.
- Pre-hotfix code state: wiring PHASE26D helpers `_detect_software_observation_intent` / `_run_software_observation` añadidos lines 806-1133 pero **sin haber sido compilados/validados syntax en esta sesión**; pero exception es ANTES de esas líneas, por tanto el hotfix de routing NO interfiere.
- Bug commit state: typo `_os_id.join` y `_os_id.exists` introducido en el código existente del `_ensure_identity_loaded` (Task6 G/T6.3 Identity Structural Boot). Revisar fecha última modificación del archivo para confirmar si el typo se introdujo en la sesión anterior que añadió T6/T7.

### USER_MESSAGE_CLASS
Dos clases de mensaje reales de Alex reproducidas:
1. **Clase A (FALLO A reproducido 3 veces)**: Pregunta sobre el sistema / routing con keywords que disparan SD bridge classifier score≥2. Texto exacto: `"por qué la GUI real sigue creando chat_sd_* y entra directamente a Self-Development antes del PHASE 26D."`
   - Clasificación SD bridge: `kind=TASK score=2 (verb_hit=True object_hit=True self_ref_hit=False) threshold_hit=True`
   - chat_sd_* task_id creado PERO falla antes de ejecutar loop.
2. **Clase B (FALLO B, última repetición)**: Pregunta mostrando registros de error `"muestra lo que esta registrado"`.
   - Tanto Clase A como Clase B terminan en el MISMO traceback.

### EXCEPTION_TYPE
- **Type**: `AttributeError` (builtin).
- **Message sanitizado**: `module 'os' has no attribute 'join'` (300 chars máx por policy).
- **Exception object (sanitized, NO secrets)**: type=`<class 'AttributeError'>`.

### TRACEBACK (completo, 6 niveles, sanitizado sin secretos)
```
Traceback (most recent call last):
  File "C:\xampp\htdocs\Digital Optimus\runtime_v1\optimus_user_agent.py", line 5548, in _worker_free_text
    final_answer = self._reason_free_text(user_text)
  File "C:\xampp\htdocs\Digital Optimus\runtime_v1\optimus_user_agent.py", line 2154, in _reason_free_text
    ctx = self._build_reasoning_context(user_text)
  File "C:\xampp\htdocs\Digital Optimus\runtime_v1\optimus_user_agent.py", line 1591, in _build_reasoning_context
    ident = self._ensure_identity_loaded()
  File "C:\xampp\htdocs\Digital Optimus\runtime_v1\optimus_user_agent.py", line 1418, in _ensure_identity_loaded
    _id_path = _os_id.join(_runtime_root, "state", "identity_family_origin_v1.json")
AttributeError: module 'os' has no attribute 'join'
```
**TB tail adicional (6 líneas en tb_tail_sanitized array de __last_ua_error.json)**:
```
    ident = self._ensure_identity_loaded()
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "...optimus_user_agent.py", line 1418, in _ensure_identity_loaded
    _id_path = _os_id.join(_runtime_root, "state", "identity_family_origin_v1.json")
               ^^^^^^^^^^^
AttributeError: module 'os' has no attribute 'join'
```

### FILE
- **Único archivo con el bug**:
  - `C:\xampp\htdocs\Digital Optimus\runtime_v1\optimus_user_agent.py`
- **No hay errores en módulos importados externos**: pywin32, Pillow, stdlib son correctos.
- **No hay errores en foundation**: visual_observation.py, sd_planner, local_answer_router, etc. = INTACTOS.

### FUNCTION
- **Función con el typo directo**: `_ensure_identity_loaded` (signature: `def _ensure_identity_loaded(self) -> Dict[str, Any]`).
- **Llamadores confirmados (2)**:
  1. `_build_reasoning_context` L1591 → llama ident.
  2. `_reason_free_text` L1825 → carga ident en segundo punto.
- **Ambos llamadores disparan el mismo error mientras `_identity_loaded == False` y `_identity_cache` no esté populado**.

### LINE (2 líneas con typo — ambas requieren fix)
1. **LINE 1418 (primero que salta el error, TB top)**:
   - Actual buggy: `_id_path = _os_id.join(_runtime_root, "state", "identity_family_origin_v1.json")`
   - Correcto: `_id_path = _os_id.path.join(_runtime_root, "state", "identity_family_origin_v1.json")`
2. **LINE 1420 (segundo typo, también falta .path)**:
   - Actual buggy: `if _os_id.exists(_id_path):`
   - Correcto: `if _os_id.path.exists(_id_path):`

### CALLER (call stack orden INWARD desde GUI al bug)
1. **GUI TK Chat Window → Event SEND_ENTER (GUI hilo principal) → `_dispatch_free_text` (después perfil detector)**.
2. **WORKER_FREE_TEXT hilo (thread worker separado, Tk-safe via after)** → función `_worker_free_text` línea **5548** → llama `self._reason_free_text(user_text)` después de intentar SD bridge si aplica.
3. **PUENTE SD BRIDGE (si aplica Clase A)**: `_classify_selfdev_vs_conversation` → score≥2 → kind=TASK → `_run_self_dev_pipeline` Crea `chat_sd_<uuid>` → luego ALGÚN punto interno (o después de fallback) → llama razonamiento general → L5548 → `_reason_free_text`.
4. **`_reason_free_text` L2154** → invoca `self._build_reasoning_context(user_text)` antes de entrar a PHASE 26C/26D/27A.
5. **`_build_reasoning_context` L1591** → `ident = self._ensure_identity_loaded()`.
6. **`_ensure_identity_loaded` L1405-L1549** → con lock, si `_identity_loaded=False` carga desde storage → typos L1418 y L1420.

### ROUTE_BEFORE_EXCEPTION (ruta exacta seguida SIN saltos)
**Para CLASE A (pregunta chat_sd_*):**
```
GUI SEND_ENTER
 → profile_detector ("Alex" → OK, persist)
 → WORKER thread worker_free_text
   → CLASIFICADOR SD BRIDGE: verb_hit=True + object_hit=True → score=2 ≥ threshold=2 → _sd_branch_used=True
     → task_id = "chat_sd_" + uuid[:10] (CREADO ✅ → FALLO A symptom)
     → ws=SelfDevWorkspace.create_from_core snapshot preparado
     → try SD_BRIDGE pipelina
       → Dentro, en algún momento necesita identity o falla en progreso
       → EXCEPTION (SD_BRIDGE_TOPLEVEL_FAIL try L5523 general capture)
       → _sd_branch_used = False (FORCE fallback a conversación normal)
     → END SD BRIDGE fallback
   → if not _sd_branch_used: L5538 → entra a CONVERSACIÓN
     → _reason_free_text L5548
       → _build_reasoning_context L2154
         → _ensure_identity_loaded L1591
           → L1418 _os_id.join ✖️ → ATTRIBUTEERROR (MISMO root cause)
 → EXCEPTION capturada L5568 worker general
 → GUARDAR data/__last_ua_error.json
 → construir mensaje "Ups tuve un problema interno" ES
 → history append
 → _ui_finalize → _append_msg optimus → GUI botón entry re-enable
```

**Para CLASE B ("muestra lo que esta registrado"):**
```
GUI SEND_ENTER
 → profile_detector OK
 → WORKER thread
   → SD BRIDGE classifier: score? probablemente score<2 → NO chat_sd_*
   → directly CONVERSACIÓN path
     → _reason_free_text L5548
       → _build_reasoning_context L2154
         → _ensure_identity_loaded L1591
           → L1418 _os_id.join ✖️ → ATTRIBUTEERROR
 → MISMO fallo, MISMO failsafe msg.
```

### FAILSAFE_TRIGGERED
- **Trigger 1**: `SD_BRIDGE_TOPLEVEL_FAIL` (L5523) → try general except Exception as _sd_top_e.
  - Guarda `LOG.exception SD_BRIDGE_TOPLEVEL_FAIL` y activa `_sd_branch_used=False` (fallback to conversation).
- **Trigger 2 (PRINCIPAL para mensaje GUI)**: `WORKER_FREE_TEXT_UNHANDLED_EXCEPTION` (L5568 `except Exception as _wk_e`).
  - Acciones: tb_lines collect, LOG.exception line 5572 (aparece 6 veces en log PID2256), `_LAST_UA_ERROR = dict`, persist JSON `data/__last_ua_error.json`, idioma=ES → `final_answer = "Ups… tuve un problema interno al razonar (está registrado)..." L5617`.
- **Trigger 3 UI**: `_ui_finalize()` L5647 → try re-enable chat_send_button y chat_input_entry.

### USER_AGENT_SURVIVED
- **¿Sobrevivió UA?** → **SÍ (100% WORKING)**.
- Checks supervivencia (de log PID2256 y screenshots Alex):
  - PID 2256 sigue vivo.
  - GUI sigue respondiendo (screenshots: Alex envió 4 mensajes, 4 respuestas fail-safe recibidas).
  - Sistema de continuidad: `"mis funciones locales siguen vivas y no me he cerrado."` del mensaje.
  - Tcl_AsyncDelete: delta = 0 (ningún crash Tcl desde restart 13:07).
  - SINGLE_INSTANCE = 1 vivo.
  - `PowerShell visible al startup = NO` (FreeConsole L2).
  - Botón Enviar re-habilitado después de cada failsafe (accesible para el siguiente mensaje).

---

## RELACIÓN FALLO A ↔ FALLO B (ROOT CAUSE UNIFICADO)

```
┌─────────────────────────────────────────────────────────────┐
│ ROOT CAUSE ÚNICO — TIPO OS.ATTR TYPO                        │
│ archivo: optimus_user_agent.py                               │
│ L1418: _os_id.join    → DEBE SER _os_id.path.join           │
│ L1420: _os_id.exists  → DEBE SER _os_id.path.exists         │
└─────────────────────────────────────────────────────────────┘
             ↓ (cualquier mensaje → carga identidad si _identity_loaded=False)
             ↓
    ┌─────────────────────────────────────┐
    │ AttributeError module 'os' no join  │
    └─────────────────────────────────────┘
      ↙                              ↘
[SD branch SI activa]            [SD branch NO activa]
Clase A msg score≥2               Clase B msg score<2
chat_sd_* TASK CREADO (FALLO A)    direct conversation
  → SD pipeline FAILS             → _reason_free_text
  → fallback conv                       ↓
  → _reason_free_text           FALLO B (mensaje Ups)
       ↓
   FALLO B (mismo mensaje Ups)

1 ROOT → 2 SYMPTOMS (FALLO A + FALLO B).
FIX MÍNIMO: 2 líneas L1418 y L1420.
```

## STATUS EVIDENCE CAPTURE
- [x] Traceback completo runtime (6 niveles, 6 repeticiones)
- [x] Excepción (tipo/mensaje/archivo/función/línea x2)
- [x] Ruta antes excepción (SD vs conversación)
- [x] 14 campos obligatorios §0B HOTFIX2 completados
- [x] Relación FALLO A y B = UNIFICADO mismo root
- [x] __last_ua_error.json leído
- [x] gui_message_trace.log revisado (truncado a sesiones viejas; el actual no captura traces)
- [x] Baseline .dev_f8_f15 INTACTO (no se ha tocado)
- [ ] FIX mínimo aplicado (próximo paso)
- [ ] py_compile exit=0
- [ ] UA RESTART + HEALTHCHECK
