## Flow replay: guardar un flujo web como función reproducible

Cuando una acción web se hace **más de una vez** (login en un panel, reiniciar un servidor
desde su consola, rellenar un formulario recurrente, descargar un export), deja de hacerse a
mano: se **graba una vez y se promueve a función del registry**. Es la doctrina del issue 0087
aplicada a la navegación — el registry crece convirtiendo secuencias repetidas en operaciones
de un solo paso, no inflando funciones existentes.

Grupo de capacidad: `flow-replay`. Página madre: `docs/capabilities/flow-replay.md`. Graba con
el grupo `web-proxy`; destila y reproduce con `flow-replay`.

### El patrón: grabar → destilar → reproducir

1. **Grabar** (una vez, con browser + proxy): `web_proxy` ON, haces la acción a mano,
   exportas el tramo a HAR (`query_mitm_flows --har`).
2. **Destilar**: `har_filter_flows_py_cybersecurity` (quita ruido) →
   `har_extract_calls_py_cybersecurity` (call specs reproducibles).
3. **Reproducir**, en esta jerarquía de preferencia (de barato a caro):

| Nivel | Mecanismo | Cuándo |
|---|---|---|
| **1 — HTTP puro** | `http_replay_sequence_py_infra` | **Por defecto.** Rápido, headless, scriptable. La mayoría de paneles admin funcionan con cookie de sesión + requests. |
| **2 — headless chromium** | action recipe (reutiliza `cdp_extract_recipe` + `cdp_save_storage_state`) | Token dinámico firmado en cliente, challenge JS obligatorio, WAF con fingerprint. |
| **3 — chromium visible + humanizado** | `cdp_click_xy_human`, `cdp_move_mouse_human` | Headless detectado/bloqueado. Último recurso. |

**Empieza SIEMPRE por el Nivel 1.** Solo baja de nivel cuando el anterior demuestre no
reproducir el efecto. Construir el runner de Nivel 2/3 por adelantado, sin un caso que lo
exija, es especular (KISS): se monta cuando un flujo real falle en HTTP puro.

### Flujo de autoría (cómo guardar una función-acción nueva)

1. Grabar el flujo y exportar el HAR del tramo.
2. `har_filter_flows` + `har_extract_calls` → boceto de la secuencia. El agente **lee** el
   HAR (es texto) e identifica los 2-4 requests que producen el efecto (auth + acción +
   confirmación), descartando el resto.
3. Parametrizar: marcar los valores variables (ids, tokens) como `{{param}}`; definir las
   reglas `extract` para los tokens que una respuesta genera y otro request consume.
4. Validar el replay con `http_replay_sequence`. Si reproduce el efecto sin navegador → Nivel 1.
5. **Promover a función del registry**: delegar a `fn-constructor` una función-acción nombrada
   con verbo (`reboot_vps_server_<panel>`, `login_<panel>`, `export_<panel>_report`) que
   internamente llama a `http_replay_sequence` con su secuencia fija, recibe los parámetros
   del caller y resuelve los secretos desde `pass`/vault. Tag de grupo `flow-replay` + el
   dominio que toque (infra, cybersecurity, …). `fn index` + usar en el mismo turno.

### Reglas duras de seguridad

- **El HAR es un secreto**: lleva cookies/tokens en crudo. Gitignored, no subir a Gitea, no
  indexar, borrar tras destilar. El output de `har_extract_calls` también, hasta sustituir por
  `{{param}}`.
- **Secretos a `pass`/vault**, jamás hardcodeados en la función-acción.
- **Replay con efectos = peligroso.** Una acción destructiva o irreversible (reiniciar, borrar,
  pagar, enviar) NUNCA se reproduce a ciegas: la función-acción exige confirmación o un flag
  explícito (`confirm=True` / `--yes`) antes de disparar.
- `http_replay_sequence` usa `verify_tls=True` y sigue redirects por defecto; la extracción
  JSON es dot-path simple, no JSONPath completo.

### Anti-patrones

| Anti-patrón | Por qué es malo | Sustituir por |
|---|---|---|
| Repetir el flujo a mano cada vez | No capitaliza; lento; propenso a error | Grabar una vez → función-acción |
| Reescribir requests inline en un heredoc/app cada vez | Reinvento, sin telemetría | Función-acción que llama `http_replay_sequence` |
| Empezar por chromium headless "por si acaso" | Más caro y frágil que HTTP puro | Nivel 1 primero, bajar solo si falla |
| Hardcodear cookie/token del HAR en el código | Secreto filtrado + caduca | `{{param}}` desde `pass`/vault |
| Commitear el HAR o el output crudo de extract | Filtración de credenciales | Tratar como secreto, gitignored |
| Replay ciego de un POST destructivo | Daño irreversible | Confirmación / flag explícito |

### Relación con otras reglas

- [[registry_first]] — buscar/reutilizar antes de escribir; la función-acción se delega a
  `fn-constructor`, no se escribe inline.
- [[function_growth_and_self_docs]] — el registry crece por promoción de composiciones
  repetidas a funciones one-shot (issue 0087); esto es ese patrón para la navegación.
- [[registry_calls]] — invocar las funciones del grupo por los patrones canónicos (MCP /
  `fn run` / heredoc que importa).
- Grupo `web-proxy` (`docs/capabilities/web-proxy.md`) — la captura que alimenta la Fase 0.
