# HOTFIX 3 — PRE-ROUTER (SPECIFIC CAPABILITY > GENERIC SELF-DEV CLASSIFIER)
## Informe Final Oficial · 13 Secciones A-M

---

## A. PRE-ROUTER ROOT CAUSE

| Campo | Valor |
|---|---|
| Archivo | `C:\xampp\htdocs\Digital Optimus\runtime_v1\optimus_user_agent.py` |
| Función / Contexto | `_worker_free_text` — SD BRIDGE Paso 3 (comentario L5377) |
| Líneas clave (antes fix) | L5549–L5574 originales: `_classify_free_text_intent()` se ejecutaba **PRIMERO** y luego `_run_self_dev_pipeline`. No existía ninguna llamada a `_detect_software_observation_intent()` ni a `_run_software_observation()` DENTRO de `_worker_free_text`. |
| Condición exacta | `_classify_free_text_intent()` retorna `_cls_meta = {kind:"TASK", score:2, threshold_hit:true}` cuando se cumplen 2 señales de `verb_hit` + `object_hit`. |
| Threshold | `score ≥ 2` definido en `_classify_free_text_intent` para promover `kind=TASK`. |
| ¿Por qué `"observa TRAE OBSERVE_ONLY"` producía TASK? | 1) Verbos clasificados genéricamente: `observa` = verb_hit=true. 2) Objeto código/self-dev: el clasificador SD captura objeto genérico de trabajo → object_hit=true. 3) Suma 1+1 = score=2 → `threshold_hit=true` → kind=TASK → `_run_self_dev_pipeline` → `chat_sd_<uuid>` → SelfDevelopment busca `foundation/*.py` (NUNCA entra al razonamiento libre PHASE26D) → Software Observation FAIL (0 evidencia TRAE, 0 Functional Map). |
| Llamada a `_reason_free_text` PHASE26D antigua | L2631 existía PERO NUNCA SE ALCANZABA para mensajes tipo observación, porque el SD bridge capturaba primero y retornaba desde el worker. |

---

## B. CALL GRAPH ANTES (FAIL — Incidente Reportado §0B)

```
USER MESSAGE  ("observa TRAE OBSERVE_ONLY functional map + evidence buckets")
   │
   ▼
LIGHTWEIGHT_CHAT enqueue free-text task → _worker_free_text daemon thread
   │
   ▼
PRE SELF-DEV CLASSIFIER  (L5543 _classify_free_text_intent)
   ├─ verb_hit   = True   ("observa" verb match en generic SD vocab)
   ├─ object_hit = True   (match objeto genérico de tarea)
   ├─ self_ref_hit=False
   ├─ score=2  →  threshold_hit=True
   └─ kind = TASK
   │
   ▼
L5615  _run_self_dev_pipeline(user_text, cls_meta)
   │
   ▼
L5088  crea  chat_sd_<uuid4>   (carpeta runtime_v1/data/self_dev/chat_sd_*/)
   │
   ▼
SelfDevelopment (SelfDevelopmentV2 / SelfDevWorkspace INSPECT-ONLY)
   ├─ busca foundation/*.py, *.md, *.json  (búsqueda código interno)
   ├─ NO detecta TRAE
   ├─ NO accede a VisualSoftwareObservation
   ├─ NO Functional Map
   └─ NO evidence buckets
   │
   ▼
USER recibe:  "=== Tarea Completada (id=chat_sd_435fde23b3) ==="  + reporte inspección foundation/*.py
RESULTADO = INCIDENTE §0B  →  SOFTWARE_OBSERVATION_ROUTING = FAIL
```

---

## C. CALL GRAPH DESPUÉS (FIX OK — SPECIFIC > GENERIC)

```
USER MESSAGE  ("observa TRAE OBSERVE_ONLY functional map + evidence buckets")
   │
   ▼
LIGHTWEIGHT_CHAT enqueue free-text task → _worker_free_text daemon thread
   │
   ▼
┌──────────────────────────────────────────────────────────────────┐
│ HOTFIX3 §3/§4 PRE-ROUTER  (L5405-L5498  ANTES  SD BRIDGE)       │
│  Principio: SPECIFIC_CAPABILITY_INTENT  >  GENERIC_CLASSIFIER    │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│  A1. _get_foreground_window_info()                               │
│  A2. globals()["_detect_software_observation_intent"](msg)       │
│       → intent_found=True,  target_hint="trae",                  │
│         observe_only_explicit=True                               │
│  A3. SI intent=True  →  FORZAR _chat_sd_created_forced_false=True│
│  A4. globals()["_run_software_observation"](msg, AlexAuth, flags_out)│
│       └─ §11 STRICT_TARGET_MODE = (target_hint !="")             │
│       └─ VisualSoftwareObservation(authorized_targets=["trae"])  │
│       └─ OBSERVE_ONLY  →  4 buckets  OBSERVED/INFERRED/VERIFIED/UNKNOWN│
│       └─ Functional Map si ventana visible                       │
│  A5. SI observation_return_OK & len(msg)>16  →  final_answer = msg│
│      _software_observation_handled = True                        │
│      SD BRIDGE  +  QUESTION  +  _reason_free_text  =  SKIP      │
└──────────────────────────────────────────────────────────────────┘
   │
   ▼ (si A5=TRUE, salta todo lo demás)
SI  software_observation_handled
   ▼
ROOT.AFTER(0, ui_finalize)   →  USER recibe reporte observación
   └─ SI app está abierta → Functional Map + Evidence Buckets
   └─ SI app NO está abierta →  STATUS=TARGET_NOT_FOUND  (§11 estricto)


SI NO hubo observation (pregunta / conversación / self-dev real):
   │
   ▼
BLOQUE §8/§9 QUESTION DETECTION (L5499-L5533)
   ├─ ends_q / starts_q regex starters
   ├─ _cap_q_pat → "¿puedes mejorarte?" → QUESTION_KIND=CAPABILITY
   ├─ _sys_q_pat → "¿por qué creaste tarea SD?" → QUESTION_KIND=SYSTEM
   └─ GENERIC preguntas → QUESTION_KIND=GENERIC
   │
   ▼
BLOQUE SD BRIDGE (L5534-L5598) — SKIP SI observation_handled O question_sin_imperativo
   ├─ SI es_question  Y  NO has_imperative_mix (build/sandbox/candidato)
   │     →  cls_meta["kind"] = CONVERSATION ; threshold_hit=False  → TASK=false
   │
   └─ SI _is_task (threshold_hit  kind=TASK)
          │
          ▼
          _run_self_dev_pipeline → crea chat_sd_<uuid> CORRECTAMENTE
          (solo para misiones SD REALES, no para observation)
```

---

## D. CAMBIO MÍNIMO (archivos y rangos de líneas)

NO hay routers nuevos. NO hay hardcod `if "TRAE" in msg`. NO hay archivos observer duplicados. Se reutilizan helpers existentes de foundation.

| Archivo | Líneas | Descripción |
|---|---|---|
| `runtime_v1/optimus_user_agent.py` | L5405–L5498 | **PRE-ROUTER bloque A** (§3/§4). Inserción de SPECIFIC SOFTWARE_OBSERVATION INTENT HANDLER justo después de inicializar `final_answer` y ANTES del try/except SD BRIDGE. Usa `globals()/locals() _detect_software_observation_intent` y `_run_software_observation` (sin import circular). Setea `final_answer` y `_software_observation_handled = True` → skips todo. |
| `runtime_v1/optimus_user_agent.py` | L5499–L5533 | **PRE-ROUTER bloque B** (§8/§9). QUESTION detection: `_ends_q / _starts_q / _cap_q_pat / _sys_q_pat` → `_is_question=True`, `_question_kind` con 3 buckets (CAPABILITY / SYSTEM / GENERIC). |
| `runtime_v1/optimus_user_agent.py` | L5534–L5598 | **SD BRIDGE con QUESTION BYPASS** (§8/§9). Si `_is_question AND NOT _has_imperative_mix` → fuerza `cls_meta["kind"]="CONVERSATION"`, `threshold_hit=False` → TASK=false. Añade atributo diagnóstico `_last_pre_router_trace` (§19 punto REAL chat_sd_). |
| `runtime_v1/optimus_user_agent.py` | L893–L904 | **Fallback target_hint token directo** (regex `(?:aplicación|app|programa|software)\s+(\S+)`) captura nombres con underscores tipo `APP_QUE_NO_EXISTE_928374` que los patrones `{2,40}` de espacio no atrapaban. |
| `runtime_v1/optimus_user_agent.py` | L941–L949 | **§11 STRICT_TARGET_MODE binario**. `STRICT_TARGET_MODE = bool(target_hint)`. Si STRICT=True → `defaults_safe=[]` (sin Notepad/Explorer fallback) y NO foreground append. |
| `runtime_v1/optimus_user_agent.py` | L1015–L1025 | **§11 STRICT fallback suppression**. `if not target_resolved and not STRICT_TARGET_MODE:` → la ventana fallback "primera visible" SÓLO opera cuando target_hint está ausente. Si target_hint está presente → STATUS=TARGET_NOT_FOUND limpio. |
| `runtime_v1/optimus_user_agent.py` | L1032–L1044 | **§11 STATUS=TARGET_NOT_FOUND mensaje**. Modo estricto muestra texto: `"No pude localizar una ventana abierta que corresponda al objetivo explícito '<target>'. STATUS=TARGET_NOT_FOUND."` |
| `runtime_v1/__hf3_test_runner.py` | (creado) | Runner standalone 7 TESTS + simulación PRE_ROUTER diagnóstico (§19). Stubs typing/win32gui/tkinter. Slice helpers L806-L1044 via exec en namespace. Escribe `hf3_test_results.json`. |
| `runtime_v1/__hf3_restart_ua.ps1` | (creado) | Kill pythonw existentes → SCHTASKS /End → SCHTASKS /Run → Sleep 10s → healthcheck count/PID/log/TCL/TRAY_DIAG/SCHEDULED_STATE. |
| `runtime_v1/optimus_user_agent.py` | L1447 / L1449 | **PRESERVAR HF2 §22**. `_os_id.path.join(...)` L1447 intacto. `_os_id.path.exists(...)` L1449 intacto. NO revierten a `os.join/os.exists`. |

---

## E. TEST1–TEST7 Resultado Individual y Evidencia

Fuente evidencia: `C:\xampp\htdocs\Digital Optimus\hf3_test_results.json` (última ejecución). `ALL_PASS=true`; 7/7 PASS; arrays `FAILURES=[]` vacíos.

| # | Test ID | Input | PASS | Evidencia clave en JSON |
|---|---|---|---|---|
| 1 | TEST1_TRAE | `"Optimus, observa únicamente la aplicación TRAE que está abierta en mi PC. No inventes evidencia. MODE=OBSERVE_ONLY. Functional Map. Evidence buckets OBSERVED/INFERRED/VERIFIED/UNKNOWN."` | ✅ PASS | `SOFTWARE_OBSERVATION_INTENT=true`, `CHAT_SD_CREATED=false`, `FINAL_ROUTE=SOFTWARE_OBSERVATION`, `STRICT_TARGET_MODE=true`, `AUTHORIZED_TARGETS_LIST=["trae"]`, `STATUS=TARGET_NOT_FOUND` (TRAE no abierto durante test standalone, expected según §11). |
| 2 | TEST2_NOTEPAD | `"Optimus, observa Notepad y dime qué componentes puedes ver. No modifiques nada."` | ✅ PASS | `SOFTWARE_OBSERVATION_INTENT=true`, `CHAT_SD_CREATED=false`, `FINAL_ROUTE=SOFTWARE_OBSERVATION`, `STRICT_TARGET_MODE=true`, `STATUS=TARGET_NOT_FOUND` (Notepad no abierto; test standalone, Alex prueba manual). |
| 3 | TEST3_NOEXIST | `"Observa la aplicación APP_QUE_NO_EXISTE_928374."` | ✅ PASS | `SOFTWARE_OBSERVATION_INTENT=true`, `TARGET_HINT="app_que_no_existe_928374"` (fallback regex underscore OK), `STRICT_TARGET_MODE=true`, `STATUS=TARGET_NOT_FOUND` exact (§11 TARGET RESOLUTION ESTRICTO), `CHAT_SD_CREATED=false`. |
| 4 | TEST4_SD_REAL | `"Investiga en sandbox una posible mejora interna para una capacidad de prueba y construye un candidato sin modificar Core."` | ✅ PASS | `SOFTWARE_OBSERVATION_INTENT=false`, `QUESTION=false`, `TASK=true`, `CHAT_SD_CREATED=true`, `FINAL_ROUTE=SELF_DEVELOPMENT`, `SELF_DEV_PRE_ROUTER_MATCH=true`, `CLASSIFY.kind=TASK score=2 threshold_hit=true`. (SD REAL funciona, no se rompió). |
| 5 | TEST5_CAP_Q | `"¿puedes mejorarte?"` | ✅ PASS | `QUESTION=true`, `QUESTION_KIND=CAPABILITY`, `TASK=false`, `CHAT_SD_CREATED=false`, `FINAL_ROUTE=REASONING_QUESTION`, `CLASSIFY.kind=CONVERSATION score=0 threshold_hit=false`. (§8 OK, bypass TASK). |
| 6 | TEST6_SYS_Q | `"¿por qué creaste una tarea de Self-Development?"` | ✅ PASS | `QUESTION=true`, `QUESTION_KIND=SYSTEM`, `TASK=false`, `CHAT_SD_CREATED=false`, `FINAL_ROUTE=REASONING_QUESTION`, `CLASSIFY.kind=CONVERSATION score=0`. (§9 OK, bypass TASK). |
| 7 | TEST7_COMPUESTA | `"Observa Notepad, identifica una capacidad funcional que te falte comparándolo contigo y, si realmente falta, investiga cómo construir un candidato en sandbox."` | ✅ PASS | `FIRST_ROUTE=SOFTWARE_OBSERVATION` (§10 OBS FIRST DEV SECOND), `SOFTWARE_OBSERVATION_INTENT=true`, `TARGET_HINT="notepad"`, `CHAT_SD_CREATED=false` (antes observation), `CHAT_SD_CREATED_BEFORE_OBSERVATION=false`. (Classifier aunque marca kind=TASK score=2 threshold_hit=true → es bypassed por observation_handled). |

**Resumen E2E RUN_FLAGS importantes (test TEST1/2/3):**
```
SELF_DEV_CODE_SEARCH_BEFORE_OBSERVATION = 0    (antes PRE_ROUTER era >0 ahora es 0)
VISUAL_OBSERVATION_INVOKED = true
CORE_MODIFIED = false
DESKTOP_MUTATION = false
OWNER_AUTH_SESSION_OWNER = "Alex"
```

---

## F. CHAT_SD

Demostración exacta de cuándo sí/no se crea `chat_sd_<uuid>` después de HF3 (según §19 punto REAL classification trace).

| Escenario | CHAT_SD_CREATED | Específico JSON |
|---|---|---|
| **Observation Request** (Test1 TRAE / Test2 Notepad / Test3 Inexistente) | ❌ false | `CHAT_SD_CREATED=false`, `SELF_DEV_CLASSIFIER_BYPASSED=true`, `SPECIFIC_INTENT=SOFTWARE_OBSERVATION`, `FINAL_ROUTE=SOFTWARE_OBSERVATION` |
| **SelfDevelopment Request REAL** (Test4 Sandbox candidato) | ✅ true | `CHAT_SD_CREATED=true`, `SELF_DEV_PRE_ROUTER_MATCH=true`, `SELF_DEV_CLASSIFIER_BYPASSED=false`, `CLASSIFY.kind=TASK score=2 threshold_hit=true`, `FINAL_ROUTE=SELF_DEVELOPMENT` |
| **Question: Capacidad** (Test5 ¿puedes mejorarte?) | ❌ false | `CHAT_SD_CREATED=false`, `QUESTION_KIND=CAPABILITY`, `CLASSIFY.kind=CONVERSATION`, `FINAL_ROUTE=REASONING_QUESTION` |
| **Question: Sistema** (Test6 ¿por qué creaste tarea SD?) | ❌ false | `CHAT_SD_CREATED=false`, `QUESTION_KIND=SYSTEM`, `CLASSIFY.kind=CONVERSATION`, `FINAL_ROUTE=REASONING_QUESTION` |
| **Misión Compuesta (Test7): OBS primero, SD después** | ❌ false ANTES observation | `CHAT_SD_CREATED_BEFORE_OBSERVATION=false`, `FIRST_ROUTE=SOFTWARE_OBSERVATION`. Después de Functional Map real, si hay gap, SD podrá iniciar en 2ª fase (no durante PRE_ROUTER). |

---

## G. TARGET RESOLUTION (§11 ESTRICTO)

| Input target_hint | STRICT_TARGET_MODE | Autorización List | Resultado STATUS |
|---|---|---|---|
| `"trae"` | ✅ true | `["trae"]` | TRAE=TRAE (match exacto). Si TRAE abierto → hwnd/título/exe poblados. Si cerrado → `STATUS=TARGET_NOT_FOUND` (NO fallback Notepad/Explorer por §11 estricto). |
| `"notepad"` | ✅ true | `["notepad"]` | Notepad=Notepad (match exe notepad.exe). Si Notepad abierto → TARGET_APPLICATION_RESOLVED=true. Si cerrado → `STATUS=TARGET_NOT_FOUND` (sin defaults). |
| `"APP_QUE_NO_EXISTE_928374"` | ✅ true | `["app_que_no_existe_928374"]` | `STATUS=TARGET_NOT_FOUND`  (exact como §15 Test3 pide). |
| `target_hint = None` (mensaje sin app concreta tipo `"observa lo que tengo delante"`) | ❌ false | `[foreground_title, foreground_exe, Notepad, Explorer, ...]` | Defaults + foreground fallback + 1ª ventana visible (comportamiento amigable existente preservado). |

---

## H. HOTFIX2 REGRESSION (§22 PRESERVAR HF2)

| Verificación HF2 | Valor / Estado | Líneas |
|---|---|---|
| `_os_id.path.join(...)` — Llamada cargar identidad | ✅ INTACTO. NO `os.join` | L1447 |
| `_os_id.path.exists(...)` — Gate archivo identity_family | ✅ INTACTO. NO `os.exists` | L1449 |
| Flujo reasoning normal `"hola como estas"` | ✅ PASS (no reaparece `AttributeError: module 'os' has no attribute 'join'`). Verificado en sesión anterior al HF3. | — |
| Typo `os.join` / `os.exists` anywhere en UA source | ✅ 0 ocurrencias. Grep sobre optimus_user_agent.py no encuentra. | — |

---

## I. PROCESS / STARTUP (§20 ANTES y DESPUÉS)

| Estado | USER_AGENT_PROCESS_PRESENT | PID | CMDLINE (pythonw UA) | SINGLE_INSTANCE_COUNT | SCHEDULED_TASK_STATE |
|---|---|---|---|---|---|
| ANTES (§0C después cierre forzado Alex x large input) | ❌ false | None | 0 procesos pythonw con optimus_user_agent.py | 0 | Ready / desconocido (tray desaparecido) |
| DESPUÉS (restart oficial vía SCHTASKS ps1) | ✅ true | **11172** | `pythonw.exe -B runtime_v1/optimus_user_agent.py` | **1** (SINGLE) | **En ejecución** |

Evidencia: `runtime_v1/__hf3_restart_ua.log`:
```
COUNT_BEFORE=0  →  SCHTASKS /END  →  SCHTASKS /RUN →  COUNT_AFTER=1
NEW_PID=11172
LOG_PATH=.../logs/optimus_runtime_pid11172.log EXISTS=True
TCL_ASYNC_DELETE_COUNT=0
pid=11172 baseline_ok=True pystray_alive=True
SCHEDULED_TASK_STATE:  En ejecución
```

Evidencia actual (healthcheck live `__hf3_healthcheck_current.log`):
```json
{
  "COUNT_PYW_UA": 1,
  "PID_LIST": ["11172"],
  "SCHEDULED_TASK_STATE": "En ejecución",
  "USER_AGENT_ALIVE": true,
  "SINGLE_INSTANCE": true
}
```

---

## J. TRAY (§21)

| Item | Valor | Fuente |
|---|---|---|
| TRAY_RECOVERED_AFTER_UA_RESTART | ✅ **true** | `__hf3_restart_ua.log` L12-L20 (9 eventos TRAY_DIAG consecutivos) |
| TRAY_DIAG · TASKBAR_CREATED_MSG_ID | msg_id=49261 | L12 |
| TRAY_DIAG · WNDCLASS_REGISTERED | atom=49702 `OptimusV1_Tray_WC2` | L13 |
| TRAY_DIAG · TRAY_WINDOW_CREATED | hwnd=0xF04B6 | L14 |
| TRAY_DIAG · TRAY_HWND | 984246 | L15 |
| TRAY_DIAG · ICON_LOADED_GRAY | GRAY optimus_tray_gray.ico | L16 |
| TRAY_DIAG · TRAY_ICON_LOADED | GRAY hicon=0x31069D | L17 |
| TRAY_DIAG · TRAY_NIM_ADD_RESULT | ok=True state=GRAY tip_len=15 | L18 |
| TRAY_DIAG · TRAY_MESSAGE_LOOP_STARTED | yes | L19 |
| TRAY_DIAG · ICON_LOADED_GREEN | **GREEN** ico=optimus_tray_green.ico hicon=0x15505AF | L20 |
| Nota §21 | NO es bug adicional. Desaparición tray fue causada por cierre forzado proceso Alex (§0C). Restart normal lo recupera. | |

---

## K. LARGE INPUT INCIDENT (§23 NO ARREGLAR AHORA)

| Item | Valor |
|---|---|
| LARGE_INPUT_FREEZE_INCIDENT | OBSERVED |
| Causa reportada | Alex pegó accidentalmente un prompt extraordinariamente largo destinado a TRAE en el input de Optimus. |
| GUI después | Tk "Not Responding" → Alex → cerrar forzado proceso → tray desaparece. |
| Conclusión HONESTA | **NO se concluye NORMAL_SELF_DEV_FREEZES_GUI=true**. No hay evidencia independiente. Large input accidental de origen externo. |
| Implementación guard en ESTE HF3? | **NO** (§23 prohíbe). Registrado solo como CANDIDATO futuro. |
| FUTURE_HARDENING_CANDIDATE list | `INPUT_SIZE_GUARD` · `ASYNC_LONG_INPUT_HANDLING` · `TK_RESPONSIVENESS_HARDENING` |

---

## L. ESTABILIDAD (§24)

| Campo | Valor | Observación |
|---|---|---|
| USER_AGENT_ALIVE | ✅ true | Healthcheck live: COUNT_PYW_UA=1 PID=11172 |
| SINGLE_INSTANCE | ✅ true | 1 sólo proceso pythonw con UA (COUNT_AFTER=1; ningún duplicado) |
| TCL_ASYNC_DELETE_DELTA | ✅ **0** | Baseline post-restart. 0 eventos Tcl_AsyncDelete en log. Hotfix estabilidad runtime anterior preservado (FreeConsole + _shutdown_lock). |
| TRAY_RECOVERED | true | (Sección J, 9 eventos TRAY_DIAG + ICON GREEN) |
| Baseline frozen `.dev_f8_f15` | ✅ intacto | 0 modificaciones al baseline en este HF3. |

---

## M. INVARIANTES (§25 — Todos Intactos)

| Invariante | Valor Esperado | Cumplido |
|---|---|---|
| `REAL_MUTATION_ENABLED` | false | ✅ (OBSERVE_ONLY everywhere; sandbox self-dev nunca promueve Core) |
| `SOFTWARE_OBSERVATION_MODE` | OBSERVE_ONLY | ✅ (VisualSoftwareObservation Session Gate OwnerAuth Alex; flags RUN_FLAGS=OBSERVE_ONLY) |
| `own_model` | false | ✅ (sin cambios; LLM API OpenAI external) |
| `brain_version` | 0.0.0-empty | ✅ (sin promoción core autónoma) |
| `CORE_AUTO_PROMOTION` | false | ✅ (test report siempre owner_app_req=SI → Alex decide, no automático) |
| CreatorAuthorityRoot intacto | Sí | ✅ (NO touch identity files; HF2 path fixes preservados) |
| Constitution intacta | Sí | ✅ (NO modificado state/constitution ni identity) |
| Kill Switch intacto | Sí | ✅ (NO tocar kill_switch files en ningún momento) |
| NO compras / NO suscripciones / NO compromisos financieros (§W) | 0 | ✅ (NO API keys purchases; NO Stripe; NUEVA_AUTORIDAD_FINANCIERA_W = Alex exclusivo) |
| NO modificar `C:\xampp\htdocs\Digital Optimus\.dev_f8_f15` | 0 bytes cambio | ✅ |
| NO activar voz | — | ✅ |
| NO activar móvil | — | ✅ |
| NO introducir nueva autonomía mouse/keyboard | 0 | ✅ (OBSERVE_ONLY; NO click automático; NO keys) |

---

==========================================================
## 27. STATUS FINAL
==========================================================

**PRE_ROUTER_FIXED_READY_FOR_ALEX_TEST**

> Explicación STATUS según §27:
> - Todos los checks técnicos de ingeniería PASARON (py_compile x2, tests standalone ALL_PASS, UA PID 11172 single instance, TRAY recovered 9 diag, TCL=0, invariants §25 intactos, HF2 regression check OK).
> - NO se ha certificado aún la prueba manual por Alex (§28). Por eso: NO es ALEX_MANUAL_TEST=PASS.
> - Listo para que Alex ejecute 4 pruebas GUI humanos definidas en §0 test real.

==========================================================
## 28. MUY IMPORTANTE — Lista de prueba manual pendiente Alex
==========================================================

**READY_FOR_ALEX_MANUAL_TEST = true**

⚠️ **NO ALEX_MANUAL_TEST = PASS (aún no ocurrió — §28)**

Pruebas GUI manuales que Alex ejecutará para certificar el fix realmente en vivo:
1. **(a) OBS TRAE REAL** — Mensaje `"Optimus, observa únicamente la aplicación TRAE que está abierta en mi PC. MODE=OBSERVE_ONLY. Functional Map. Evidence buckets OBSERVED/INFERRED/VERIFIED/UNKNOWN."` → Esperado: **NO se crea ningún `chat_sd_*`**, UA responde con Functional Map + buckets directamente.
2. **(b) CAPABILITY Q** — `"¿puedes mejorarte?"` → Esperado: **NO inicia Tarea SD**. Respuesta de razonamiento conversacional sobre capacidades actuales.
3. **(c) SYSTEM Q** — `"¿por qué creaste una tarea de Self-Development?"` → Esperado: **NO inicia Tarea SD**. Respuesta explicativa sobre clasificación SD.
4. **(d) SD REAL OK** — `"Investiga en sandbox una posible mejora interna para una capacidad de prueba y construye un candidato sin modificar Core."` → Esperado: SI crea `chat_sd_<uuid>` correctamente, SelfDevelopment pipeline, reporte sandbox sin tocar Core.

==========================================================
## 29. STOP (Fin HOTFIX 3)
==========================================================

**DETENCIÓN TOTAL HASTA NOTIFICACIÓN DE ALEX**.

🚫 NO iniciar otra fase.
🚫 NO desarrollar otra capacidad nueva.
🚫 NO promocionar candidatos al Core.
🚫 NO activar mouse/teclado.
🚫 NO ejecutar misiones nuevas automáticamente en Optimus UA real.

Alex y ChatGPT revisarán primero este informe.
— FIN HOTFIX 3.
