From a77a6f2fd0d515f6c2452f2c687d36f77330b460 Mon Sep 17 00:00:00 2001 From: Cristian Felipe Cruz Buitron Date: Sat, 19 Sep 2026 20:15:45 +0000 Subject: [PATCH] docs(tmux-host): documentar gotcha de reinicio completo del NAS (2026-09-19) Tras un corte de luz real, la sesion tmux "lab" se recreaba sola pero Claude Code nunca arrancaba adentro -- distinto al caveat de persistencia de sesion ya documentado (ese es "el proceso muere, el contenedor sigue vivo"; esto es "el host completo se apaga y arranca de cero"). Documenta las dos causas encontradas (claude nunca se lanzaba tras recrear la sesion; riesgo de carrera con el mount de /media/HDD-Storage) y el fix aplicado en scripts/tmux-host/healthcheck.sh. Co-Authored-By: Claude Sonnet 5 --- .../arquitectura/sesion-tmux-persistente.md | 60 ++++++++++++++++++- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/workloads/docs-portal/docs/arquitectura/sesion-tmux-persistente.md b/workloads/docs-portal/docs/arquitectura/sesion-tmux-persistente.md index b533bcc..fd83cf8 100644 --- a/workloads/docs-portal/docs/arquitectura/sesion-tmux-persistente.md +++ b/workloads/docs-portal/docs/arquitectura/sesion-tmux-persistente.md @@ -230,9 +230,13 @@ falla: contenedor. - **Existencia de la sesión tmux `lab`** (`tmux has-session`): si no existe, **sí se recrea automáticamente** (`tmux new-session -d -s lab - -c `) — es solo recuperar el propio entorno de trabajo del - contenedor, no tocar infraestructura externa, así que es seguro - hacerlo sin intervención humana. + -c `, seguido de `tmux send-keys -t lab claude Enter` — ver + gotcha "sesión recreada pero sin Claude Code adentro" más abajo) — es + solo recuperar el propio entorno de trabajo del contenedor, no tocar + infraestructura externa, así que es seguro hacerlo sin intervención + humana. Si `WORKDIR` todavía no está montado (ver gotcha siguiente), + no se crea la sesión esa vuelta — se reintenta en el próximo ciclo en + vez de crearla mal posicionada. Todo evento (chequeo ok, falla de red, sesión recreada) queda en `/DATA/AppData/k3d-lab-v3/tmux-host/logs/health.log` — persistente en @@ -247,6 +251,56 @@ contenedor con `-e HEALTHCHECK_INTERVAL_SEC=60` (solo para pruebas en un contenedor descartable — nunca cambiar esto en el `tmux-host` real sin volver a 1800 después). +## Gotcha: sesión recreada, pero sin Claude Code adentro (reinicio completo del NAS, 2026-09-19) + +Distinto al caveat de persistencia de sesión de más abajo (ese cubre "el +*proceso* muere pero el contenedor sigue vivo" — cerrar la sesión `lab` a +mano, o un crash del propio `claude`). Este es otro escenario: **el HOST +completo se apaga y vuelve a arrancar desde cero** (corte de luz, no un +`docker restart` ordenado) — reordena cuándo arrancan Docker, la red y los +montajes de `/DATA`/`/media/HDD-Storage` entre sí, algo que un +`docker restart` normal nunca ejercita porque el host ya estaba arriba. + +Tras un corte de luz real, se encontró que el usuario se reconectó a la +sesión `lab` y encontró un shell vacío, no Claude Code corriendo. Dos +causas distintas, ambas corregidas: + +1. **La sesión tmux SÍ se recreaba sola** (confirmado en `health.log`: el + contenedor arrancó y la sesión `lab` quedó recreada en cuestión de + segundos), pero `check_tmux_session()` nunca lanzó `claude` adentro — + solo garantizaba que existiera el *shell*, no que el proceso de Claude + Code estuviera corriendo. El diagrama de arquitectura de este mismo doc + siempre mostró `T --> CC["proceso claude"]` como si fuera automático, + pero el código nunca lo implementó — el hueco quedó invisible mientras + nadie pasó por un reinicio completo real del NAS (en un `docker + restart` normal, el `claude` que ya estaba corriendo dentro de la + sesión simplemente sigue vivo, porque ahí el proceso *no* muere). + **Fix:** `check_tmux_session()` ahora llama `launch_claude_in_session()` + (`tmux send-keys -t lab claude Enter`) justo después de crear la sesión + — solo cuando la crea de cero, nunca sobre una sesión que ya existe (no + se reinyecta `claude` sobre un pane con trabajo en curso). +2. **Riesgo de carrera no ejercitado todavía, pero real:** `WORKDIR` + (`/DATA/AppData/k3d-lab-v3/lab-cruzcloud`) llega vía el symlink absoluto + `/DATA/AppData -> /media/HDD-Storage/AppData` (ver el gotcha del symlink + más arriba). Si el storage externo (`/media/HDD-Storage`) tarda en + montarse en el host más de lo que tarda Docker en arrancar este + contenedor — plausible después de un corte de luz, no de un simple + restart —, `mkdir -p "$LOG_DIR"` fallaba en silencio (`set -u` sin + `-e`) y ese arranque quedaba *sin ningún rastro* en el log, y + `tmux new-session -c "$WORKDIR"` habría creado la sesión mal + posicionada (o fallado) contra un directorio que todavía no existe. + **Fix:** `wait_for_workdir()` reintenta con backoff (pasos de 5s, hasta + `STARTUP_MOUNT_WAIT_MAX_SEC=120` por defecto) a que `WORKDIR` exista + antes de tocar el log o crear la sesión; si sigue sin existir pasado + ese máximo, se registra el error explícitamente y se reintenta en el + siguiente ciclo (30 min) en vez de fallar una sola vez y quedarse así. + +**Validado en vivo:** imagen reconstruida (`tmux-host:test-fix`) y probada +en un contenedor descartable aparte (mismos mounts de `/DATA` y +`/media/HDD-Storage`, sin tocar el `tmux-host` real) — `docker stop` + +`docker start` (arranque desde cero, no `restart`) recreó la sesión `lab` +con `claude` corriendo adentro sin intervención manual, en ~1 segundo. + ## Qué sobrevive a qué | Evento | ¿Sobrevive la sesión tmux (`lab`)? | ¿Sobrevive el login de Claude Code? |