Sin uso actual, y el host está evaluando capacidad de memoria para la
Etapa 2 del ADR 0006 (Meilisearch) con swap bajo presión. Se quita del
app-of-apps para liberar los recursos del namespace `monitoring`
(Grafana, Prometheus, Alertmanager, kube-state-metrics,
prometheus-operator -- estos dos últimos venían en CrashLoopBackOff
desde hace 37 días, ~8000 reinicios cada uno, conexión rechazada
contra el apiserver in-cluster -- y los 3 node-exporter).
Reversible: reagregar ambos archivos re-despliega el stack completo
vía Helm/kustomize sin pasos manuales. Sin pérdida de datos -- el
namespace monitoring no tenía ningún PVC, confirmado antes de borrar
(kubectl -n monitoring get pvc -> vacío).
Se agregó el finalizer resources-finalizer.argocd.argoproj.io a ambas
Applications (monitoring-app, monitoring-governance) antes de este
commit para que Argo CD borre en cascada los recursos desplegados al
podarlas, no solo el objeto Application -- sin eso quedarían pods
huérfanos corriendo sin liberar memoria.
commerce.cruzcloud.net (medusa-svc) has no route at "/" — Medusa only
serves /health, /app (admin), /store, etc. lab-agent's generic public
domain check flagged the resulting 404 as an anomaly every cycle even
though the service is healthy.
Adds a Traefik Middleware (redirectRegex) scoped to the commerce host
that 301s "/" to "/app", so the DNS/routing layer owns the entry point
instead of every client (including monitoring) having to know to
append /app manually. Regex includes the host explicitly because the
same Ingress also routes media.cruzcloud.net and shares
router.middlewares at the Ingress-annotation level.
Documenta el cambio a Telegram (silencioso para info, hilos al
recuperarse, log adjunto), la pausa nocturna 06:00-23:00 con su
tensión sin resolver con la ventana de medusa-deploy, la activación
del timer de systemd (60 min, bajado de 15 para reducir costo) con el
gotcha de Environment=HOME= para systemd --user, y el costo mensual
estimado actualizado.
17 corridas/día en vez de 68. Nota importante: el costo por corrida
sube al perder la ventaja del cache tibio de Claude Code (~1h TTL,
corridas espaciadas 60 min lo pierden casi siempre) -- el ahorro real
es ~1.5-2x, no 4x. También documenta el trade-off de latencia de
detección (~70 min en vez de ~25 min hasta detectar un problema).
Timer activo desde 2026-08-26. Documenta el hallazgo en vivo: el
manager de systemd --user de devops arranca con HOME=/DATA (el de
/etc/passwd), no con el override de /etc/profile.d/zz-devops-home.sh
que solo aplica a shells interactivas -- sin Environment=HOME=... en
la unidad, claude -p habría fallado la autenticación en cada corrida
del timer, silenciosamente. Se detectó y corrigió antes de activar,
corriendo el servicio manualmente vía systemctl --user start con el
entorno real como último paso de validación.
Actualiza la sección de Notificaciones: formato con íconos por tipo de
evento, log completo adjunto como documento, nivel "info" silencioso
(disable_notification), y respuestas en hilo cuando un recurso
accionado se recupera solo -- con la limitación conocida de que un
desbloqueo manual (borrando la entrada de state.json) pierde el
message_id y no queda threadeado. Validado en vivo con el canario.
Actualiza docs/arquitectura/agente-monitoreo.md: canal de notificación
cambiado de ntfy a Telegram Bot API (con la evidencia de la prueba de
entrega), horario activo 06:00-23:00 con su justificación de costo, la
tensión sin resolver con la ventana de medusa-deploy (00:00-06:00, no
se solapa con el horario activo del agente), y la estimación de costo
mensual (~US$60-65, basada en las corridas reales medidas).
Documentación de gobernanza y arquitectura del agente lab-agent:
lista blanca aprobada, diseño de seguridad (--allowedTools "" en vez
de un Bash tool con patrón, por la vulnerabilidad de coincidencia por
prefijo encontrada en vivo), autenticación por login de suscripción, y
evidencia completa de la prueba end-to-end del 2026-08-26.
Agrega docs/arquitectura/agente-monitoreo.md como referencia técnica y
documento de gobernanza del wrapper headless de diagnóstico/corrección
(scripts/lab-agent). Cubre la lista blanca de acciones automáticas
aprobada, por qué Claude corre con --allowedTools "" en vez de un Bash
tool con prefijo (coincidencia por prefijo permite inyección de
comandos, confirmado en vivo), el rediseño de autenticación a login de
suscripción en vez de API key, y la evidencia completa de la prueba
end-to-end del 2026-08-26 (DRY_RUN, ejecución real, rate limit/bloqueo,
2 bugs encontrados y corregidos).
| Trigger | Deployment con `readyReplicas < replicas` o condición `Available=False` durante **≥10 minutos consecutivos** |
| Namespace elegible | `ecommerce` (todos los deployments detectados ahí en el momento de la corrida) |
| Excepción | `medusa-deploy` — el deployment real de "commerce-backend" en la terminología de `CLAUDE.md` (confirmado en vivo 2026-08-25: no existe un deployment llamado literalmente `commerce-backend`) — solo elegible si además la hora **local** del host está entre **00:00–06:00** |
| Namespaces excluidos siempre | `argocd`, `kube-system`, cualquier otro namespace de plataforma |
| Trigger | Contenedor no está en estado `running` durante ≥10 min, **o** la API de Gitea Actions reporta un run en estado `running` atascado por más de 10 min sin terminar (señal del incidente de runner zombie del 2026-08-16) |
| Degradación segura | Si no hay `GITEA_TOKEN_FILE` configurado o la API falla, esa señal se omite — nunca dispara una acción sobre una lectura no verificada, solo queda la señal de "contenedor caído" |
| Excluidos siempre | `gitea`, `nginxproxymanager`, `cloudflared` |
### 3. Fuera de alcance automático — SIEMPRE (solo diagnóstico + notificación)
(`"ok":true`) y contenido recibido tal cual en Telegram. Gotcha
encontrado durante la prueba: el primer intento falló con `400 chat not
found` porque el `chat_id` pegado correspondía a otro bot — el `chat_id`
de un usuario es el mismo across bots, pero Telegram igual devuelve
`chat not found` si *ese bot puntual* nunca recibió un mensaje de esa
persona. Se resolvió confirmando el `chat_id` real vía `getUpdates` del
bot correcto.
**Formato:** cada notificación lleva un ícono según su naturaleza
(✅ acción ok, 🛑 acción falló/rechazada, 🚨 alerta de seguridad,
❌ error operativo, 👀 solo diagnóstico) y el log completo de esa
corrida va adjunto como documento (`sendDocument`), no solo como ruta —
útil para revisar desde el celular sin acceso a shell.
**Notificación silenciosa y respuestas en hilo (2026-08-26):** el nivel
`info` (nada elegible, todo diagnóstico rutinario) se manda con
`disable_notification=true` — no interrumpe; acciones, fallas y alertas
de seguridad sí suenan. Cuando se ejecuta una acción correctiva, el
`message_id` de Telegram queda guardado por recurso en `state.json`
(`telegram_message_id`); si ese recurso se recupera solo en una corrida
posterior, se manda un aviso silencioso como **respuesta** (hilo) al
mensaje original antes de limpiar el estado — agrupa visualmente todo
un incidente. Limitación conocida: si un humano desbloquea el recurso a
mano borrando su entrada de `state.json` (ver más abajo), el
`message_id` se pierde con esa entrada, así que ese caso puntual no
queda threadeado — solo el "se recuperó solo" está cubierto hoy.
Validado en vivo con el canario: acción real → `message_id` capturado →
canario parcheado a una imagen sana → reply en hilo confirmado,
silencioso, al recuperarse.
## Horario activo y costo
**Pausa nocturna (`ACTIVE_HOURS_START`/`END`, hora local del host):**
activo `06:00`–`23:00`, pausado `23:00`–`06:00`. El script chequea esto
como lo primero que hace tras inicializar logging — si está fuera de
horario, sale **antes** de tocar `kubectl`/`docker`/`curl` o invocar
`claude -p`, así que la pausa ahorra el costo completo de la corrida,
no solo la notificación. El timer de systemd además solo dispara dentro
de esa ventana (`OnCalendar=*-*-* 06..22:00:00`) — la doble
verificación es deliberada: si alguien edita la unidad de systemd sin
tocar `lab-agent.env` (o corre el script a mano), el chequeo interno
sigue protegiendo.
**Tensión sin resolver con la ventana de `medusa-deploy`:** la ventana
de auto-restart para `medusa-deploy` (`COMMERCE_BACKEND_WINDOW_*`,
`00:00`–`06:00`) **no se solapa** con el horario activo del agente
(`06:00`–`23:00`). Esto significa que, en la práctica, `medusa-deploy`
nunca es candidato real a auto-restart: la única ventana en la que la
política lo permitiría es exactamente cuando el agente está pausado y
ni siquiera corre. La regla sigue viva en el código (por si el horario
activo cambia más adelante) pero hoy es efectivamente inalcanzable.
Pendiente de decisión: mover la ventana de `medusa-deploy` a que caiga
dentro del horario activo, o aceptar que ese recurso queda cubierto
solo por diagnóstico/notificación manual.
**Estimación de costo mensual — actualizada 2026-08-26, frecuencia
bajada de 15 a 60 min explícitamente para reducir costo:**
| | |
|---|---|
| Corridas/día (17h activas ÷ 60 min) | 17 |
| Costo por corrida | ~US$0.04–0.12 — **más alto por corrida que a 15 min**: el cache de prompt de Claude Code dura ~1h, y con corridas espaciadas 60 min casi siempre expira entre una y la siguiente, así que la mayoría de las corridas pagan cache "fría" en vez de "tibia" |
# Redirige solo la raíz exacta de commerce.cruzcloud.net a /app (admin de
# Medusa) — el regex incluye el host a propósito: esta Middleware se
# referencia desde el mismo Ingress que también enruta media.cruzcloud.net,
# y sin el host en el regex un request a la raíz de ese otro dominio
# también matchearía (ambas rutas comparten Ingress -> mismas
# router.middlewares). Si el regex no matchea, Traefik deja pasar el
# request sin modificarlo.
redirectRegex:
regex:"^https?://commerce\\.cruzcloud\\.net/$"
replacement:"https://commerce.cruzcloud.net/app"
permanent:true
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.