Documentar cambio a Telegram, pausa nocturna y costo estimado
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).
This commit is contained in:
1 parent
5014903c51
commit
e493f7d39e
1 file changed
+70
-11
@@ -172,20 +172,79 @@ no se purgaron.
|
|||||||
|
|
||||||
## Notificaciones
|
## Notificaciones
|
||||||
|
|
||||||
Canal: [ntfy](https://ntfy.sh) — sin sistema de notificación previo en
|
**Canal: Telegram Bot API** (reemplaza a ntfy, cambiado 2026-08-26 por
|
||||||
el lab, se eligió la opción sin infraestructura nueva (tópico público
|
preferencia — no por costo, ver sección de costo abajo). Bot creado
|
||||||
de ntfy.sh, nombre privado difícil de adivinar) para validar la prueba
|
manualmente vía [@BotFather](https://t.me/BotFather); el token vive en
|
||||||
end-to-end sin bloquear en instalar y exponer un contenedor propio.
|
`TELEGRAM_BOT_TOKEN_FILE` (dueño `devops`, `600` — **no** root-only,
|
||||||
Migrar a un ntfy self-hosted (mismo patrón que gitea/nginxproxymanager/
|
mismo criterio que `GITEA_TOKEN_FILE`: el servicio corre como `devops`
|
||||||
cloudflared) es un cambio de una sola variable (`NTFY_URL`) cuando se
|
por el login de suscripción, un archivo `root:root` le sería ilegible).
|
||||||
decida.
|
`TELEGRAM_CHAT_ID` no es secreto, va directo en `lab-agent.env`.
|
||||||
|
|
||||||
|
El mensaje se manda como texto plano, sin `parse_mode`: el motivo que
|
||||||
|
devuelve Claude es texto libre y puede traer `_`, `*`, `[`, `]` — con
|
||||||
|
Markdown/MarkdownV2 esos caracteres rompen el parser de Telegram (`400
|
||||||
|
Bad Request`) si no se escapan con cuidado. Se prioriza entrega
|
||||||
|
confiable sobre formato.
|
||||||
|
|
||||||
|
**Validado en vivo 2026-08-26** con el mismo código que usa
|
||||||
|
`notify_send()` (lectura del token, `sendMessage` vía `curl
|
||||||
|
--data-urlencode`, formato `[title]\nmessage`): entrega confirmada
|
||||||
|
(`"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.
|
||||||
|
|
||||||
|
## 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/15: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:**
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| Corridas/día (17h activas ÷ 15 min) | 68 |
|
||||||
|
| Costo por corrida (medido en la prueba e2e, Sonnet) | ~US$0.018–0.045 con cache tibia; ~US$0.12 en frío (primera corrida del día, tras 7h de pausa el cache de prompt ya expiró) |
|
||||||
|
| Estimado diario (1 corrida fría + 67 tibias) | ~US$2.10 |
|
||||||
|
| **Estimado mensual (× 30 días)** | **~US$60–65** (rango US$35–90 según variación real de cache) |
|
||||||
|
|
||||||
|
Basado en solo ~7 corridas reales medidas durante la prueba — no es un
|
||||||
|
promedio estadísticamente robusto, es una primera estimación para
|
||||||
|
decidir si el timer se activa. Revisar el costo real después de la
|
||||||
|
primera semana en producción y ajustar frecuencia/modelo si hace falta.
|
||||||
|
|
||||||
## Pendiente antes de activar el timer en continuo
|
## Pendiente antes de activar el timer en continuo
|
||||||
|
|
||||||
- **Confirmación explícita del propietario del lab** para habilitar el
|
- **Confirmación explícita del propietario del lab** para habilitar el
|
||||||
timer de systemd (Paso 4 original) — no se activa automáticamente
|
timer de systemd — no se activa automáticamente solo por haber
|
||||||
solo por haber pasado la prueba end-to-end.
|
pasado la prueba end-to-end ni por tener el costo estimado.
|
||||||
- Unidad systemd corriendo como `devops` (no root), con límites de
|
- Unidad systemd de usuario (`systemctl --user`, corre como `devops`,
|
||||||
CPU/memoria.
|
no `root`), con límites de CPU/memoria (`CPUQuota`, `MemoryMax`).
|
||||||
|
Requiere `loginctl enable-linger devops` (una vez, con sudo) para que
|
||||||
|
seguir corriendo sin sesión interactiva activa.
|
||||||
- Opcional: `GITEA_TOKEN_FILE` para activar la señal de "runner
|
- Opcional: `GITEA_TOKEN_FILE` para activar la señal de "runner
|
||||||
atascado" vía API de Gitea Actions (hoy se omite, degradación segura).
|
atascado" vía API de Gitea Actions (hoy se omite, degradación segura).
|
||||||
|
- Decidir la tensión con la ventana de `medusa-deploy` (ver arriba).
|
||||||
Reference in new issue
Block a user