Files
feadulta/docs/handoff-tecnico-rafa-issues-174-175-2026-07-15.md
rafa 69e849d38e Sync: guardar en el historial el trabajo de las ultimas semanas que solo vivia en el disco
Este repo local tenia origin apuntando al Gitea local (localhost:3000), que Rafa
declaro archivado el 2026-06-28 (commit 962f33a, desarrollo movido a
gitea.feadulta.com). Ese memo nunca llego a este checkout: main quedo congelado
y todo el trabajo real de las ultimas 3+ semanas se fue commiteando solo en la
rama fix/multiidioma-portada-132 (ya fusionada a main sin perdida, commit
2504666), mientras que ademas se acumulaban 78 cambios sin commitear en el
working tree que nunca llegaron a NINGUN historial de git.

Este commit consolida esos cambios sueltos: TTS multi-voz (tts_*.py), scripts
de traduccion (translate_haiku.py, pretranslate_en_haiku.py, sync_translations_to_prod.py),
mu-plugins nuevos desplegados a prod (fea-beta-feedback, fea-cloudflare-realip,
fea-legacy-redirect, fea-gsc-verification, fea-support-campaign, fea-ui, etc.),
scripts de mantenimiento de enlaces/cartas, capturas E2E (tools/e2e/shot_*.cjs)
y documentacion de sesiones recientes.

Excluido deliberadamente (no es codigo versionable): tts-voices/ (3.3GB de
muestras de audio para clonacion de voz, anadido a .gitignore), logs/ (logs de
ejecucion, anadido a .gitignore), y 2 ficheros vacios accidentales + 2 copias
duplicadas sueltas en la raiz que ya existen en su ubicacion correcta.
2026-07-15 20:03:21 -04:00

6.2 KiB

Handoff técnico para Rafa — issues #174 y #175

Alcance

Preparación técnica solamente. No aplicar en producción desde aquí.


Issue #174 — cierre autónomo de la carta (publicar + rotar)

Regla funcional confirmada por Inma/Mixbot

La rotación que ya funcionó hoy manualmente por WP REST API para la carta 735 es esta, y solo para el post ES:

  1. nueva carta → añadir cat 6 (carta actual)
  2. la que estaba en cat 6 → quitar cat 6, añadir cat 22 (semana pasada), manteniendo cat 21 (archivo acumulativo)
  3. la que estaba en cat 22 → quitar cat 22, dejar solo cat 21
  4. no tocar traducciones en este paso

Decisión pendiente para Rafa

Hay dos caminos válidos:

Opción A — adaptar rotate_cartas.php a ES-only

Pros:

  • reutiliza lógica ya existente y conocida en el repo
  • más coherente con el toolkit actual de scripts
  • fácil dejar DRY-RUN + APPLY=1

Contras:

  • hay que modificar el script actual porque hoy rota todos los idiomas
  • si Mixbot publica por REST y la rotación la hace otro script aparte, el flujo queda repartido en dos piezas

Opción B — que Mixbot haga la rotación por WP REST API

Pros:

  • ya está validado en vivo hoy
  • mantiene toda la operación editorial en el mismo sitio donde ya se publica la carta
  • evita acoplar la decisión editorial a un script server-side adicional

Contras:

  • la lógica queda fuera del repo de scripts PHP si no se documenta bien
  • conviene dejarla muy explícita para no divergirse del comportamiento esperado

Recomendación técnica

Mi lectura: cualquiera vale, pero elegiría según quién vaya a mantenerlo:

  • si Rafa quiere la lógica versionada y centralizada en el repo, mejor A: rotate_cartas.php ES-only
  • si Inma/Mixbot ya tienen el flujo sólido y prefieren autonomía total desde su lado, mejor B: REST API desde Mixbot, con la lógica documentada en el issue/runbook

Si Rafa elige A (script ES-only), propuesta concreta

Crear una variante mínima o adaptar rotate_cartas.php con estas reglas:

  • entrada: CARTA=<es_id>
  • lookup solo en idioma es
  • localizar:
    • actual_es = post con cat 6
    • pasada_es = post con cat 22
    • nueva_es = CARTA
  • operaciones:
    • pasada_es pierde 22, conserva 21
    • actual_es pierde 6, gana 22, conserva 21
    • nueva_es gana 6 y conserva/gana 21
  • nunca tocar posts EN/FR/IT/PT
  • mantener modo DRY-RUN

Dry-run deseable para Rafa

Salida ideal del dry-run:

  • nueva_es=#54495 -> +6 (+21 si faltaba)
  • actual_es=#54254 -> -6 +22 (mantiene 21)
  • pasada_es=#53984 -> -22 (mantiene 21)
  • translations untouched

Decisión funcional que conviene dejar escrita

Para evitar ambigüedad futura, dejar explícito en el issue o en el script:

  • 21 es acumulativa y la conservan todas las cartas archivables
  • 6 y 22 son mutuamente excluyentes
  • la rotación editorial inicial afecta solo al ES
  • las traducciones rotan/publican en un paso posterior independiente

Issue #175 — endpoint subir-avatar

Base ya existente

El sistema actual ya tiene casi todo:

  • frontend lee user_meta('foto_perfil')
  • face_crop_avatar.py ya resuelve recorte/centrado de cara
  • regen_avatars.php ya existe para regeneración/ajustes
  • caso real listo para probar: Silvia Martínez Cano, user_id=1112, slug=silvia-mtnz

Contrato recomendado

Yo le propondría a Rafa este contrato por simplicidad operativa:

Endpoint

POST /wp-json/fea/v1/subir-avatar

Auth

La misma Application Password que ya usa crear-autor (#166), con el mismo criterio de permisos.

Identificador

user_id mejor que slug.

Motivo:

  • Mixbot ya lo tiene en el roster
  • evita ambigüedades por slug cambiado / transliteraciones / colisiones
  • simplifica el lookup

Formato de entrada

multipart/form-data mejor que base64.

Motivo:

  • más natural para subir imágenes
  • menos overhead
  • encaja mejor con media_handle_sideload / manejo típico WP
  • más fácil de depurar que base64

Campo esperado

  • user_id (obligatorio)
  • file (obligatorio)

Opcionalmente:

  • crop=server|client si Rafa quiere dejar ambas puertas abiertas, aunque probablemente es overkill de entrada

Recomendación de procesamiento

Mi recomendación clara: que el endpoint NO haga face-crop complejo en la primera versión.

Mejor v1:

  • Mixbot/Inma mandan la imagen ya cuadrada
  • estándar objetivo: 1254x1254 (el que ya usáis)
  • el endpoint solo:
    1. valida usuario
    2. guarda attachment
    3. actualiza foto_perfil
    4. devuelve attachment_id, user_id, url

Pros:

  • mucho menos riesgo y menos dependencias server-side
  • evita meter OpenCV/Pillow/lógica pesada dentro del endpoint
  • más fácil de testear e idempotente
  • si mañana queréis face-crop automático, se añade en v2

Comportamiento recomendado del endpoint

  • requiere login + permiso tipo edit_others_posts (igual filosofía que crear-autor)
  • valida que user_id exista
  • acepta solo imagen (jpg, jpeg, png, webp si WP lo admite ahí)
  • crea attachment en Media Library
  • hace update_user_meta($user_id, 'foto_perfil', $attachment_id)
  • respuesta JSON:
    • user_id
    • display_name
    • attachment_id
    • url
    • updated: true

Idempotencia mínima útil

No hace falta obsesionarse en v1, pero sí conviene:

  • si se vuelve a subir otra foto para el mismo user_id, simplemente reemplazar el foto_perfil al nuevo attachment
  • opcional: si el hash del fichero coincide con el ya asignado, devolver updated:false

Caso piloto sugerido

Primera prueba con:

  • user_id=1112
  • slug=silvia-mtnz
  • imagen ya recortada por Inma/Mixbot a 1254x1254

Así la prueba valida solo el endpoint, no el pipeline de crop.


Cierres administrativos

Por estado funcional, salvo sorpresa:

  • #166 → cerrable
  • #168 → cerrable
  • #170 → cerrable

Recomendación final para Rafa

Si quiere minimizar trabajo y riesgo:

  • #174: usar la lógica que ya validó Mixbot hoy, y solo portar al repo si él prefiere centralizar
  • #175: endpoint mínimo con user_id + multipart + imagen ya cuadrada a 1254x1254

Eso deja la autonomía mucho más cerca sin meterse en una refactor rara.