# Debug Session: tcl-crash-boot-real-v2
**Project:** Digital Optimus (C:/xampp/htdocs/Digital Optimus)
**OpenedBy:** Owner Alex manual test fail after previous hotfix.
**Date:** 2026-09-19
**Status:** [OPEN]

## Bug (VERBATIM Alex):
Cmd EXACTO: `cd runtime_v1 ; python.exe -B optimus_user_agent.py`
- Intento 1: Tcl_AsyncDelete: async handler deleted by the wrong thread → termina.
- Intento 2: Tcl_AsyncDelete: async handler deleted by the wrong thread → termina.
- Intento 3: Vuelve al prompt PS inmediatamente (sin crash texto ni tray).

## 5 Falsifiable Hypotheses:

H1: **StringVar ghost interpreter global MainThread** (Lines 5622-5632 optimus_user_agent.py). 11 `tk.StringVar(value=...)` se crean EN EL MOMENTO DE IMPORTAR la clase/objeto MemoryInspectorWindow (tiempo de import top-level). Como no hay ningún `tk.Tk()` creado todavía para esas variables, tkinter crea un intérprete Tcl implícito global EN MainThread guardado en `_default_root`. Después LightweightChatWindow/StatusWindow/MemoryInspectorWindow crean tk.Tk() reales EN SUS PROPIOS daemon threads (no MainThread). El handler global único `Tcl_AsyncDelete` termina asociado a BOTH intérpretes. Cuando GC/import-finalizer corre en MainThread o el hilo UI, el delete cruza threads → crash NATIVO. REFUTE: grep que tk.StringVars son top-level/class (no inside method __init__ self.root = tk.Tk() posterior). CONFIRM: logs TK_VAR_CREATED tid=MainThread antes que ningún TK_TK_CREATED.

H2: **atexit._ua_atexit_finalizer top-level Line 320 corre antes que self.shutdown() en MainThread toca alive Tk objects de UI threads**. Register se ejecuta DURANTE IMPORT (antes que main() corre). El finalizer corre SIEMPRE cuando Py_Finalize, incluso cuando hubo crash exit antes. Dentro hay `alive_tk_objects_count`, etc. - itera objetos Tcl vivos, potencialmente en hilos distintos al MainThread → delete cross-thread handler global → crash. REFUTE: si NDJSON tiene Python_atexit_finalizer BEFORE (o sin) shutdown_clean → H2 valido.

H3: **alguien llama sys.exit/return 7 durante boot antes que el UA llegue a tray loop**, por ejemplo NamedMutex acquire, load state JSON corrupto, o alguna excepción no capturada en init. Entonces Py_Finalize se ejecuta en MainThread MIENTRAS los 11 StringVars globales + WindowStructs están inicializados parcialmente (mid-import). GC delete objetos Tcl fantasma → crash. INTENTO 3 Alex "vuelve inmediatamente al prompt sin texto" = return7 sys.exit antes. CONFIRM: FIRST_EXIT_TRIGGER NDJSON entry para exit_kind=run_return7 / sys.exit / exception uncaught.

H4: **Tray._tray_loop importa win32gui/pystray en OptimusTray thread, pero la importación WIN32/pystray ejecuta código que toca objetos Tk (para icono) EN EL THREAD TRAY, mientras MainThread sigue inicializando otros**. Race between tray thread import and __main__ StringVar ghost inicialization. CONFIRM: TK_TK_CREATED o TK_VAR_CREATED en tid que NO es MainThread NI es known UI thread (Chat/Status/Memory).

H5: **root.destroy() desde hilo equivocado en alguna ventana (lines 3954, 4943, 5124, 5170, 6484, 6567)** - aún cuando monkey-patch Misc.destroy redirect cross-thread after(0) owner, algunos root.destroy() ocurren antes de que se asigne el _dbg_owner_tid (por ejemplo, durante fallo init root). CONFIRM: FIRST_EXIT_TRIGGER = destroy_cross_before_patch.

## Observation Points required (Instrumentation sites):

O1: exit-trigger wrapper (NDJSON) on ALL:
  sys.exit(), os._exit(), return7 ALREADY_RUNNING, print(ALREADY_RUNNING),
  _stop_event.set() (lines 7825 y 7936),
  atexit._ua_atexit_finalizer (line 320),
  shutdown() first line,
  root.destroy() wrapper con stack_trace caller_thread,
  root.quit() wrapper,
  tray.stop / icon.stop wrapper.

O2: Grep StringVar line 5622 crear stack trace. Capturar tid, caller, timestamp y escribir NDJSON TK_VAR_CREATED GHOST si no existe todavía ningún Tk() creado.

O3: faulthandler.enable(ALL threads) PRIMERA LÍNEA DE EJECUCIÓN justo después del shebang antes que cualquier import tkinter.

O4: boot timestamp cronológico R0 (primer statement) - S1 import done - S2 monkey-patch aplicado (si hay) - S3 StringVars ghost creados (tid) - S4 mutex - S5 signal handlers - S6 state load - S7 tray thread spawn - T0 tray enter - T1 pystray import - H0 heartbeat first loop.

O5: 1 sola instancia cmd EXACTO Alex, poll alive 90s.

## Status Line:
[OPEN | STEP R1-R2 done. R3 instrument ongoing. R4 reproduce pending.]
