Hub

2026-05-29

viernes · 29 de mayo de 2026

Bitácora 2026-05-29

hub + hub-web-viewer — fuente única de verdad para pendientes

Sesión grande de refactor del hub. Sergio pidió hacer #399 (recorrer pendientes sin fecha) pero antes quería unificar la fuente de verdad: PENDIENTES.md y el /calendario del viewer estaban divergiendo.

Auditoría inicial

Detecté 3 pendientes en "Próximas fechas" de PENDIENTES.md que NO aparecían en /calendario:

  • #399 (admin hub) — vivía solo en PENDIENTES.md, sin proyecto.
  • #002#111 (jm-checador) — bullet sin 📅 estándar, fecha 2026-08-14 en prosa.
  • #177 (cobros-recurrentes) — usaba **(recordatorio 2027-03-01)** en vez de 📅 2027-03-01.

Decisión: eliminar PENDIENTES.md como archivo manual

Sergio: "ya no tengo esa necesidad" con el viewer publicado. Migración completa a fuente única:

  1. Viewer reescrito (commit 86dd2fa):

    • src/lib/projectPendings.ts (nuevo): parser que recorre los bodies de projects/<slug>.md, identifica sección (🎯 top / En progreso / Backlog / otra) trackeando headers, extrae #NNN/📅/⏱/prio. Helpers collectOpenPendings, groupByProject, countByPriority, collectClosedRecent (parsea "Resuelto YYYY-MM-DD [#NNN]" de bitácoras).
    • src/pages/pendientes.astro rehecho como vista derivada agrupada por proyecto, ordenada por sortProjects, dentro de cada uno top → in_progress → backlog → other con badges 📅/⏱/🔥.
    • src/pages/projects/[slug].astro: nueva sección "Pendientes abiertos" arriba del body con los pendientes del proyecto en orden recomendado.
    • src/pages/index.astro: dashboard ya no lee hub/PENDIENTES.md. Conteos, top por prioridad, cerrado reciente y disparo condicional ahora del helper nuevo.
    • src/layouts/Layout.astro: estilos .hub-anchor movidos a global.
    • src/lib/pendientes.ts eliminado (dead code).
  2. Hub (commit 79d92da):

    • PENDIENTES.md borrado.
    • _next-id (archivo nuevo) reemplaza el contador que vivía como comentario al final de PENDIENTES.md. Bumpeado a 400 → después 403 al asignar #400-#402.
    • projects/hub-admin.md (proyecto nuevo, client=personal) — #399 vive aquí.
    • projects/jm-checador.md #111: reformateado con 📅 2026-08-14.
    • projects/cobros-recurrentes.md #177: reformateado con 📅 2027-03-01.
    • ANTIGRAVITY.md: sección "Mantenimiento de PENDIENTES.md" reemplazada por "Pendientes — fuente única". Se preserva la convención de IDs y los marcadores de antigüedad (ahora calculados por el viewer).
    • 5 memorias actualizadas para quitar referencias a PENDIENTES.md como input operativo (feedback_due_date_obligatorio, feedback_spanish_mexican, feedback_keep_repos_synced, feedback_propose_quote_before_billable_work, feedback_timezone_cd_juarez).

Orden crítico al pushear

Push del viewer ANTES del hub. Si pusheas el hub primero (que borra PENDIENTES.md), el CF rebuild del viewer truena porque aún lee hub/PENDIENTES.md. Coordinación: viewer push → CF rebuild verde → hub push → segundo rebuild absorbe ambos.

#399 — barrido de fechas

Después de la migración, barrí los 295 bullets sin 📅 que quedaron en 39 archivos. Estrategia: por proyecto, Sergio elegía la asignación (esta semana / este mes / sin-fecha / mix).

active+high (40 bullets, 5 archivos, commit dc6875a):

  • poseidon-root-triage #144 → 2026-06-15.
  • machine-parity: #157 🔥 → 2026-05-30, #158 → 2026-06-02, #155+#156 → 2026-06-03.
  • orion-decommission: migración escalonada en junio (#139-#142+#021); cleanup + apagado físico (#023, #024, #400-#402 IDs nuevos) → 📅 cond:migracion-completa.
  • es-antenas-new: 10 bullets escalonados en junio (#196 Tepehuanes primero).
  • electro-ia: 15 bullets escalonados (Fase 2 → primera quincena, Fase 3 → última semana).

active+medium + sub-docs + backlog/paused (255 bullets, 34 archivos, commit 0f228c7):

  • amadeus-sprints (30): todos sin-fecha (archivo de planeación, no de ejecución).
  • vpn-clientes (22): #073 Fase 0 → 2026-05-30, resto sin-fecha.
  • backup-system (21): junio escalonado (operacional).
  • amadeus (15): próximos 10 días + checklist de deploy → 2026-06-08.
  • wireguard-jrz-elp (13): junio escalonado.
  • holbox (10): esta y próxima semana (30-may → 12-jun).
  • joyeriameza/adfsa-migration/gi-siptrunks-replacement/ia-evaluacion/cpe-benito-juarez (30): junio escalonado.
  • tareas-hijo (4): Fase 3-5 junio escalonado, Fase 6 sin-fecha (evolución continua).
  • electrosystems-network-map (4): Fase 1-3 junio, Fase 4 sin-fecha (mantenimiento perpetuo).
  • greco-cell/telcel-jacala/deportescampeon (7): junio escalonado.
  • jm-checador #286 + hub-portability "más adelante": sin-fecha.
  • network-map sub-docs (21): próxima semana.
  • projects-hub sub-docs (28): sin-fecha (design KB).
  • docs-platform (5), poseidon-storage (2): este mes.
  • amadeus-auditoria-viajes (9), horizon-casas-internet-lento (5): sin-fecha.
  • monitoring-homologation (12, paused+high): sin-fecha (proyecto pausado).
  • infra-updates (12), aprende-ingles (3): próximos 10 días.

Verificación final: 0 bullets sin 📅 en projects/.

Bug del viewer detectado al validar

Sergio reportó: "No hay página de proyecto de holbox; me da error".

Causa raíz: hasProjectFrontmatter() en content.config.ts leía solo los primeros 1500 bytes para detectar project:. Holbox tenía un last-fix: gigante (~3KB acumulado de 7 sesiones) que empujaba el cierre --- al byte 4607. El loader rechazaba el archivo en silencio y /projects/holbox/ no se generaba.

Auditoría: solo holbox era afectado hoy (era el único con frontmatter >1500 bytes), pero la vulnerabilidad existía.

Fix (commits 51a56e1 viewer + 80f648c hub):

  • Viewer: hasProjectFrontmatter() lee el archivo completo en vez de los primeros 1500 bytes. Resultado: 74 páginas (vs 73 antes del fix).
  • Hub: last-fix: de holbox reducido a 179 caracteres; historial ya estaba en la bitácora. Regla nueva en ANTIGRAVITY.md: máximo 200 chars por valor de frontmatter (incluye last-fix:; si necesitas más, va a bitácora).

Sergio confirmó: "Ya se ve holbox en viewer".

Commits de la sesión

  • 86dd2fa (viewer) — /pendientes derivado de projects/, fin de PENDIENTES.md como input.
  • 79d92da (hub) — eliminar PENDIENTES.md; fuente única en projects/.
  • dc6875a (hub) — #399 active+high (40 bullets).
  • 0f228c7 (hub) — #399 cerrado (255 bullets restantes).
  • 51a56e1 (viewer) — fix loader >1500 bytes.
  • 80f648c (hub) — limpiar last-fix gigante + regla 200-char.

Estado al cierre

  • /pendientes muestra 283 pendientes agrupados por proyecto en 31 proyectos visibles.
  • /calendario muestra 126 pendientes con fecha concreta (mayo + junio 2026, buckets vencidas/hoy/semana/mes/después).
  • /projects/<slug>/ (incluyendo holbox) muestra arriba la sección "Pendientes abiertos" con orden recomendado.
  • Dashboard / re-derivado del helper nuevo: 41 proyectos, 298 pendientes (60 alta · 192 media · 34 baja), 8 clientes, cerrado reciente.
  • _next-id en 403. PENDIENTES.md no existe más.
  • #399 cerrable en próxima sesión (todos los pendientes están fechados; falta cerrarlo formalmente como cierre de la meta-tarea).

Sesión tarde — machine-parity: migración OpenVPN → WireGuard

Pedido de Sergio: avanzar con #157.

Cerrado:

  • #157 + #158 — PC personal migrada de OpenVPN a WireGuard unificado. Diagnóstico ("diagnosticar primero"): el único gap real de paridad era 10.11.0.0/16; el server WG (VM wireguard en poseidon, 192.168.20.5, túnel 10.255.255.0/24) ya alcanza todo y hace MASQUERADE general en ens3 → solo hubo que agregar el peer .14 (sin cambios de iptables). Cliente Windows es-wg split-tunnel (Endpoint 201.174.219.154:51820, AllowedIPs enumerados + 172.16.0.0/16 oficina que agregó Sergio). Validado desde WSL: 10.11.x + 192.168.20/3.x + 172.16.x + sitios OK, internet directo. WG auto-arranca con Windows. OpenVPN retirado.
  • #156~/agy/electrosystems/ clonado en PC personal.

Otros resultados:

  • Router MikroTik de oficina (172.16.0.1): no había jump host Linux en 172.16.0.0/24 (todo dropbear). Sergio agregó 192.168.20.5 al allow del MikroTik → accesible por WG (verificado HTTP 200 / Winbox / API; SSH 58695 sigue filtrado).
  • Perfil del server WG documentado: electrosystems/servers/wireguard/README.md + fila/changelog en INVENTORY (cubre #078b/#079 de wireguard-jrz-elp). Memoria nueva reference_es_wireguard_roadwarrior.
  • Remote nas agregado en el clone de PC personal. Hallazgo: GitHub origin estaba 12 commits atrás del NAS (perfiles ares/asterisk/cpe/laptop-ia/monitoreo/nagios/l2l-telcel + regla ANTIGRAVITY.md). Reconciliado con autorización: merge nas/main (conflicto solo en INVENTORY.md, combinado) → push a NAS y GitHub; los tres en a743fd8, sin force-push.

Pendientes abiertos (nuevos): #408 (WG en celular, 6/2), #409 (proceso repetible para más clientes WG, 6/3), #410 (control de acceso fino por cliente WG, 6/4), #411 (arreglar dual-push de la laptop, 5/30). _next-id 408→412.

Commits: hub (varios machine-parity, push automático); electrosystems (perfil wireguard + merge a743fd8 pusheado a GitHub origin y NAS).


Sesión tarde (laptop trabajo) — barrido paralelo: amadeus, machine-parity, infra-updates, vpn-clientes

Pedido de Sergio: varias tareas, "todas en paralelo". Sincronicé el hub primero (estaba 21 commits atrás → pull --ff-only).

Cerrado / avanzado:

  • amadeus #249 → movido a lunes 2026-06-01 (prender ANALISIS_HOOK_CONSUMOS_ENABLED). Actualizado en amadeus.md + amadeus-consumos-milestone.md.
  • amadeus #239VERIFICADO HECHO (subagente, código al día en main): las 3 fases del scope ya están (ConsumoAnalisis + AnalizarFotoConsumoJob + AnalizadorTicketService con Antigravity vision) + extras (#247, #377, dashboard, 8 tests). "Fase 3" se hizo como heurística IA libre (D2-B), no tabla de palabras clave. Solo falta el flag (#249). Design doc amadeus-validacion-fotos.mddone.
  • machine-parity #411CERRADO. Causa: main rastreaba nas/maingit push pelón iba solo al NAS. Fix: set-upstream-to=origin/main (origin empuja a GitHub+NAS). No había divergencia real (GitHub ya tenía todo, ancestro → ff). Verificado ls-remote: local=GitHub=NAS=a743fd8.
  • infra-updates #113 → arrancado: tabla de versiones del datacenter 192.168.20.x (13/51 hosts; faltan 10.11.x por VPN). Hallazgos: 3 CentOS 6 EOL, reverse-proxy 109 updates, uisp Ubuntu 20.04 EOS. Tabla en Notas técnicas del proyecto.
  • vpn-clientes #073diseño Fase 0 cerrado al 100% (vpn-clientes/PLAN.md). Decisiones (con contexto de Sergio): instancia wg-cli separada en la VM wireguard; solo /32 por servidor, NO se rutean LANs (LAN cliente = SSH tunnel, por LANs solapadas); subredes por función + ADFSA /22; source of truth en la VM; segmentación rol-based default-amplio (flexible vía campo allow). Confirmados: DNAT 2º puerto UDP sí, ADFSA cabe en /22, piloto = ARIAS, apolo es concentrador (no gateway). Abrí #413 (scaffolding), #414 (lab), #077 → cond:fase-0b-verde.
  • vpn-clientes #413scaffolding wg-cli HECHO en projects/vpn-clientes/wg-cli/ (seed reviewable del dir que irá a la VM): peers.yaml+peers.schema.md, parse_peers.py (parser propio sin PyYAML), render-wg-cli.sh, los 4 scripts (wg-create-key/install/revoke/list), lib/common.sh, lab/README.md, .gitignore. Probado local: render conf+firewall OK, validación atrapa IP fuera de subred, guards de prod (mutan solo con --apply+--i-know-prod), dry-run no muta. 2 bugs corregidos (auto-IP-libre por heredoc → env vars; guard_not_prod bloqueaba dry-run → solo en --apply). wg genkey no probado aquí (falta wireguard-tools en la laptop) → se valida en #414.

Infra de sesión:

  • Hook SessionStart agregado a ~/.claude/settings.json (con autorización de Sergio): al iniciar sesión hace git fetch y avisa si el hub está atrasado vs origin/main. Memorias nuevas: reference_hub_sessionstart_hook, feedback_parallel_batching_no_mix.

Pendiente para próxima sesión: #414 (lab en poseidon, 6 tests de segmentación, 📅 5-jun) → su verde desbloquea el piloto ARIAS (#077).

Lección operativa: al paralelizar, NO mezclar git/SSH/config-mutante con Edits en el mismo batch — una denegación del clasificador cancela a todos los hermanos. Documentado en memoria.


Sesión noche — amadeus → monitoreo: bug 419 login por IP (#415) end-to-end

Pedido de Sergio (en cadena): anotar un bug de amadeus (419 al login por IP 192.168.20.17), gestionar un par de pendientes, y luego investigarlo/arreglarlo.

Gestión de pendientes en amadeus:

  • Capturé el bug como #413 en amadeus; moví #048 a martes 2026-06-02; cerré #051 (smoke notif viaje creado).

Investigación (read-only en prod) — el bug NO era de amadeus:

  • La VM amadeus es 192.168.20.20 (cookie electrosystems_session, SESSION_DOMAIN=null). La IP 192.168.20.17 emite es_monitoreo_session → es monitoreo (es-antenas-new). El 419 sale de esa app.
  • Reatribuido: saqué el bug de amadeus y lo recreé en es-antenas-new como #415 (nuevo ID porque #413 ya lo tenía vpn-clientes por colisión de sesión paralela — dos #413 vivos). Notas de reatribución en ambas bitácoras.
  • Abrí #416 en hub-admin: diseñar esquema de IDs con prefijo de proyecto (los #NNN globales en _next-id sin única fuente de verdad colisionan entre sesiones paralelas). _next-id 413→417.

Diagnóstico de raíz #415: monitoreo se sirve por dos paths — HTTPS por dominio (vía VM reverse_proxy que termina TLS y reenvía HTTP) y HTTP plano por IP en la LAN. Con SESSION_SECURE_COOKIE=true fijo, el navegador descarta las cookies secure sobre HTTP/IP → sin sesión ni token CSRF → 419. TrustProxies no estaba configurado (isSecure()=false en ambos paths; el login HTTPS funcionaba solo porque el navegador guarda la cookie del lado HTTPS).

Fix #415 (Sergio eligió "middleware dinámico"):

  • Nuevo app/Http/Middleware/ConfigureSecureSessionCookie.php (prepend del grupo web): fija session.secure por petición = true solo si HTTPS (directo o vía X-Forwarded-Proto). .env.example base a false. 2 tests Pest verdes. Pint OK.
  • Commit a55cddc → push → deploy (scripts/deploy.sh, 162s). Verificado en prod: HTTP/IP → cookie sin secure (login OK); X-Forwarded-Proto: https → cookie con secure. Sergio confirmó que funciona en ambos paths.

Cierre fino (post-confirmación):

  • .env de prod alineado a SESSION_SECURE_COOKIE=false (backup .env.bak-20260529-415; sin config cache → directo).
  • Horizon investigado: sano (horizon:status=running, 1 master systemd laravel-worker@1 con max-processes=10 sobre redis, queues default+aggregates). El Horizon is inactive del deploy era falso positivo: el script checaba horizon:status justo tras horizon:terminate, antes del respawn. Fix aplicado en scripts/deploy.sh (commit 81eab3b): el check se movió a después del poll de workers systemd.

Commits de la sesión:

  • es-antenas-new: a55cddc (middleware Secure dinámico #415), 81eab3b (orden de horizon:status en deploy.sh).
  • hub: varios (captura/reatribución #413#415, #048, #051, #416, cierre #415, .env, fix Horizon) — push automático.

Estado al cierre: #415 resuelto/deployado/verificado; .env prod alineado; Horizon sano + warning corregido (aplica en el próximo deploy). Abiertos para después: #416 (esquema de IDs por proyecto, hub-admin, 📅 2026-06-05).