feat(browser): auto-commit con 60 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,8 @@ Registry personal de código con búsqueda FTS. Diseñado para composición func
|
||||
- `integrity.md` — Reglas de integridad y referencias cruzadas
|
||||
- `architecture.md` — Visión general del sistema
|
||||
- `sync_setup.md` — Vincular una PC al server `registry.organic-machine.com` (env vars, `fn sync`, troubleshooting)
|
||||
- `adr/` — Architecture Decision Records: decisiones de diseño (qué se decidió y por qué)
|
||||
- `../reports/` — Reportes de trabajo: **artefacto local** (entregable de una tarea: qué se hizo, cómo se verificó, gaps). Gitignored salvo `.gitkeep`, NO sube a Gitea ni se versiona (como los vaults). Convención en `.claude/rules/reports.md`. Decisión: [ADR 0006](adr/0006-reports-folder.md)
|
||||
|
||||
## Tablas
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# ADR 0006 — `reports/` como artefacto local para reportes de trabajo
|
||||
|
||||
- **Fecha:** 2026-06-06
|
||||
- **Estado:** accepted
|
||||
|
||||
## Contexto
|
||||
|
||||
Cuando un agente termina una tarea no trivial (una auditoría, una tanda de fixes con verificación, un refactor, una investigación), el resumen ejecutable —qué se hizo, cómo se verificó, qué quedó pendiente— vivía solo en el chat de la sesión. Eso tiene tres problemas:
|
||||
|
||||
1. **Se pierde**: el chat no es consultable después; el resumen no queda en disco.
|
||||
2. **No es compartible rápido**: para pasar el resultado hay que copiar a mano del chat.
|
||||
3. **No tiene formato estable**: cada resumen sale distinto, sin garantía de evidencia ejecutable ni de declaración honesta de gaps.
|
||||
|
||||
Los contenedores existentes no encajan: los ADRs (`docs/adr/`) son decisiones de diseño; las reglas (`.claude/rules/`) son normas operativas; el diario (`docs/diary/`) es bitácora cronológica libre. Faltaba un sitio para el **entregable de una tarea concreta**: el resultado y su evidencia.
|
||||
|
||||
Punto clave de la decisión: un report **no es documentación del registry, es un artefacto** (en el sentido de `.claude/rules/artefactos.md`) — generado, con ciclo de vida propio, no código reutilizable. Y como artefacto del tipo "datos locales", se comporta como los **vaults**: no sube a Gitea ni se versiona en el git del padre.
|
||||
|
||||
## Decisión
|
||||
|
||||
Crear la carpeta `reports/` para reportes de trabajo, tratados como **artefacto local**:
|
||||
|
||||
1. **No versionados, no Gitea.** `reports/*` está en el `.gitignore` del padre (solo `reports/.gitkeep` se versiona, para mantener la carpeta presente). Un report no tiene repo propio: vive local en la máquina que lo generó. Compartir = pasar la ruta o copiar el contenido, no `git push`. Mismo trato que los vaults.
|
||||
2. **Conviven en raíz o en proyectos**, como cualquier artefacto: `reports/` (sueltos) o `projects/<p>/reports/` (del trabajo de un proyecto). Ambas rutas gitignored (`reports/*`, `projects/*/reports/`). Se permiten subcarpetas para agrupar.
|
||||
3. **No se indexan en `registry.db`.** Sin tabla `reports` ni schema (KISS) — son texto plano efímero, como los `playgrounds`.
|
||||
4. **Convención y plantilla** viven en `.claude/rules/reports.md` (versionado): nombre `NNNN-YYYY-MM-DD-slug.md`, secciones Resumen/Cambios/Verificación/Gaps, evidencia ejecutable obligatoria.
|
||||
|
||||
Un report NO sustituye a un ADR ni a una regla: si durante el trabajo aparece una decisión de diseño, va a `docs/adr/` y el report solo la referencia.
|
||||
|
||||
## Alternativas consideradas
|
||||
|
||||
- **Versionar los reports en el repo padre.** Era el enfoque inicial de este ADR; descartado: un report es un artefacto (resultado de tarea, efímero, posiblemente voluminoso o ligado a un PC concreto), no documentación estable del registry. Versionarlos ensucia el historial del padre con entregables operativos. La convención correcta es la de los vaults: local, no Gitea.
|
||||
- **Dejar los resúmenes solo en el chat.** Status quo; se pierden y no son compartibles. Es el motivo del ADR.
|
||||
- **Usar `docs/diary/`.** El diario es cronológico, libre y versionado; mezclaría notas con entregables formales y no impone evidencia ejecutable.
|
||||
- **Un ADR por tarea.** Sobrecarga el registro de decisiones con resultados operativos.
|
||||
- **Indexar los reports en `registry.db`.** Añade schema y mantenimiento para un artefacto efímero. KISS: no se indexa, como los playgrounds.
|
||||
|
||||
## Consecuencias
|
||||
|
||||
- `.gitignore` del padre gana `reports/*` (con `!reports/.gitkeep`) y `projects/*/reports/`.
|
||||
- Nueva regla `.claude/rules/reports.md` con convención + plantilla; entrada en `.claude/rules/INDEX.md`.
|
||||
- `report` se añade como tipo de artefacto en `.claude/rules/artefactos.md` (NO indexado, NO sub-repo Gitea).
|
||||
- Mención en la sección "Estructura" / "Artefactos" de `.claude/CLAUDE.md` y en `docs/README.md`.
|
||||
- Los agentes pueden escribir un report al cerrar una tarea no trivial y pasar la ruta para compartir, en vez de volcar el resumen al chat. El report queda local (no viaja por git/`fn sync` salvo que el usuario lo copie aparte).
|
||||
- Primer report: `projects/web_scraping/reports/0001-2026-06-06-browser-domain-audit-fixes.md` (local, gitignored; vive en el proyecto porque el trabajo tocó sus apps). Cada project que use reports añade `reports/*` (salvo `!reports/.gitkeep`) a su propio `.gitignore` para no subirlos a su Gitea.
|
||||
|
||||
## Relación con otras reglas y ADRs
|
||||
|
||||
- `.claude/rules/artefactos.md` — report es un tipo de artefacto; este ADR lo añade a la taxonomía.
|
||||
- `.claude/rules/reports.md` — convención operativa derivada de este ADR.
|
||||
- `.claude/rules/playgrounds.md` — mismo espíritu (artefacto local, no indexado).
|
||||
- `.claude/rules/dod_quality.md` — los reports heredan su exigencia de evidencia ejecutable y gaps.
|
||||
- [ADR 0002](0002-apps-analyses-as-dataforge-master.md) — apps/analyses SÍ son sub-repos Gitea; los reports NO (se parecen a los vaults, no a las apps).
|
||||
- [ADR 0005](0005-keep-parent-git-lean.md) — mantener el `.git` del padre ligero; no versionar reports refuerza esa línea.
|
||||
@@ -63,3 +63,4 @@ Qué se aprendió después. Útil cuando un ADR se supersede.
|
||||
| [0003](0003-orphan-tu-as-separate-function-entry.md) | TU adicional de un parent function como entrada propia | accepted |
|
||||
| [0004](0004-telemetry-driven-capability-growth.md) | Telemetria de ejecuciones de Claude como motor de crecimiento del registry | accepted |
|
||||
| [0005](0005-keep-parent-git-lean.md) | Mantener el `.git` del padre ligero: no trackear artefactos hijos, purgar historial, submódulos shallow | accepted |
|
||||
| [0006](0006-reports-folder.md) | Carpeta `reports/` para reportes de trabajo (entregable de tarea con evidencia) | accepted |
|
||||
|
||||
@@ -24,6 +24,7 @@ Indice de grupos de capacidades del registry. Cada grupo agrupa >=3 funciones qu
|
||||
| [docker](docker.md) | 38 | Operar Docker desde Go/Bash: build/run/stop, compose, networks, volumes, logs, deploys |
|
||||
| [android](android.md) | 37 | Toolbelt Android desde WSL2: adb, emuladores AVD, APK build/install, Capacitor, logcat |
|
||||
| [web-proxy](web-proxy.md) | 5 | Captura de trafico HTTP/HTTPS liviana (mitmproxy): proxy con rotacion, navegador proxeado, consulta de capturas, tee del SSE de claude. Alternativa ligera a ZAP/Burp |
|
||||
| [flow-replay](flow-replay.md) | 3 | Guardar un flujo web (login, reiniciar server, formulario) como funcion reproducible: destila un HAR a call specs y lo reproduce sin navegador (HTTP puro), con fallback a chromium headless/visible. Consume las capturas de web-proxy |
|
||||
| [metabase](metabase.md) | 106 | Operar Metabase via API REST: auth, cards, dashboards, collections, snippets, permissions |
|
||||
| [doctor](doctor.md) | 11 | Diagnostico read-only del registry: artefactos, servicios, drift, funciones huerfanas |
|
||||
| [notebook](notebook.md) | 5 | Operar Jupyter Lab colaborativo (discover/read/exec/write/kernel) |
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
# Flow Replay — Guardar un flujo web como función reproducible
|
||||
|
||||
Tag: `flow-replay`. Grupo de funciones para convertir un flujo de navegador que se hizo
|
||||
una vez a mano (login en un panel, reiniciar un servidor, rellenar un formulario) en una
|
||||
**función del registry reproducible sin intervención**. Materializa la doctrina del issue
|
||||
0087: el registry crece promoviendo secuencias repetidas a operaciones de un solo paso.
|
||||
|
||||
Filtro MCP: `mcp__registry__fn_search query="" tag="flow-replay"`.
|
||||
|
||||
Complementa al grupo [`web-proxy`](web-proxy.md): `web-proxy` **graba** el tráfico,
|
||||
`flow-replay` lo **destila y reproduce**.
|
||||
|
||||
## El patrón: grabar → destilar → reproducir
|
||||
|
||||
Tres fases, con una jerarquía de reproducción de más barato a más caro:
|
||||
|
||||
```
|
||||
Fase 0 — GRABAR (una vez, siempre con browser + proxy)
|
||||
web_proxy ON → haces la acción a mano en el navegador → exportas el tramo a HAR
|
||||
(funciones del grupo web-proxy: start_mitm_capture, launch_chromium_proxy, query_mitm_flows --har)
|
||||
|
||||
Fase 1 — DESTILAR (del HAR a una secuencia de requests)
|
||||
har_filter_flows → descarta estáticos/analytics, deja los flujos que importan
|
||||
har_extract_calls → normaliza cada flujo a una "call spec" reproducible (método, url,
|
||||
headers, cookies, body), aislando los datos de auth
|
||||
|
||||
Fase 2 — REPRODUCIR, en orden de preferencia:
|
||||
Nivel 1 HTTP puro http_replay_sequence — rápido, headless, scriptable. PREFERIDO.
|
||||
Nivel 2 headless chromium (fallback) — cuando hay token dinámico firmado en cliente,
|
||||
challenge JS o WAF con fingerprint de navegador. Reutiliza
|
||||
cdp_extract_recipe + cdp_save_storage_state (ver Fronteras).
|
||||
Nivel 3 chromium visible + acciones humanizadas — último recurso si headless es detectado
|
||||
(cdp_click_xy_human, cdp_move_mouse_human del dominio browser).
|
||||
```
|
||||
|
||||
La función-acción concreta que guardas en el registry (`reboot_<panel>_server`,
|
||||
`login_<panel>`, etc.) envuelve el nivel que funcione: idealmente una llamada a
|
||||
`http_replay_sequence` con su secuencia + parámetros, y los secretos resueltos desde
|
||||
`pass`/vault.
|
||||
|
||||
## Funciones del grupo
|
||||
|
||||
| ID | Firma corta | Qué hace |
|
||||
|---|---|---|
|
||||
| [har_filter_flows_py_cybersecurity](../../python/functions/cybersecurity/har_filter_flows.md) | `har_filter_flows(har, *, hosts, methods, drop_static, drop_analytics) -> list[dict]` | Filtra un HAR: descarta recursos estáticos y hosts de telemetría, deja los flujos candidatos a "acción". Pura. |
|
||||
| [har_extract_calls_py_cybersecurity](../../python/functions/cybersecurity/har_extract_calls.md) | `har_extract_calls(entries, *, drop_headers) -> list[dict]` | Convierte entries HAR en "call specs" normalizadas (método/url/headers/cookies/body/body_type), aislando cookies de auth y descartando headers hop-by-hop. Pura. |
|
||||
| [http_replay_sequence_py_infra](../../python/functions/infra/http_replay_sequence.md) | `http_replay_sequence(calls, *, params, extract, timeout_s, verify_tls, allow_redirects, base_headers) -> dict` | Motor de replay HTTP: ejecuta la secuencia compartiendo cookie jar, substituye `{{param}}` y extrae valores de una respuesta para inyectarlos en pasos siguientes (flujo CSRF-like). Impura. |
|
||||
|
||||
## Ejemplo canónico end-to-end
|
||||
|
||||
Destilar un HAR capturado y reproducir el flujo sin navegador. Las tres funciones se
|
||||
encadenan; la extracción del paso 1 (un token) se inyecta en el paso 2:
|
||||
|
||||
```python
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join("python", "functions"))
|
||||
from cybersecurity.har_filter_flows import har_filter_flows
|
||||
from cybersecurity.har_extract_calls import har_extract_calls
|
||||
from infra.http_replay_sequence import http_replay_sequence
|
||||
|
||||
# 1. HAR exportado por: query_mitm_flows ~/captures/traffic-*.mitm --har ~/sesion.har
|
||||
import json
|
||||
har = json.load(open(os.path.expanduser("~/sesion.har")))
|
||||
|
||||
# 2. Destilar: del ruido a la secuencia mínima
|
||||
flows = har_filter_flows(har, hosts=["panel.midominio.com"]) # solo el host del panel
|
||||
calls = har_extract_calls(flows) # call specs reproducibles
|
||||
|
||||
# 3. Reproducir (Nivel 1, HTTP puro). El token del GET inicial se inyecta en el POST.
|
||||
res = http_replay_sequence(
|
||||
calls,
|
||||
params={"server_id": "vps-42"}, # parametrizado por el caller
|
||||
extract=[{"from": 0, "type": "json", "expr": "csrf", "as": "csrf"}],
|
||||
verify_tls=True,
|
||||
)
|
||||
print(res["status"], [s["status_code"] for s in res["steps"]])
|
||||
```
|
||||
|
||||
Una vez validado, el flujo se promueve a una función-acción nombrada del registry
|
||||
(p. ej. `reboot_vps_server_<panel>`) que internamente llama a `http_replay_sequence`
|
||||
con su secuencia fija, recibe los parámetros del caller y resuelve los secretos desde
|
||||
`pass`. Esa función-acción es lo que el agente invoca en un solo paso a partir de entonces.
|
||||
|
||||
## Fronteras
|
||||
|
||||
- **No graba**: la captura es del grupo [`web-proxy`](web-proxy.md). Este grupo empieza
|
||||
con un HAR ya existente.
|
||||
- **No auto-parametriza** (todavía). `har_extract_calls` normaliza pero NO detecta solo
|
||||
qué valor es un token dinámico ni dónde se reinyecta. La parametrización (`{{param}}`)
|
||||
y las reglas de `extract` las decide el humano/agente leyendo el HAR. La detección
|
||||
automática de tokens/CSRF sería una función nueva del grupo, no una ampliación.
|
||||
- **No incluye el runner de Nivel 2/3** (browser fallback). Está especificado en el
|
||||
patrón pero no implementado: cuando un flujo real falle en HTTP puro, se construye un
|
||||
"action recipe" reutilizando casi entero `cdp_extract_recipe_py_pipelines` (mismo
|
||||
formato YAML, steps de acción en vez de extracción) + `cdp_save_storage_state_go_browser`
|
||||
para saltarse el login. No se construye por adelantado (KISS / registry-first).
|
||||
- **No gestiona secretos**: los secretos viajan como `{{param}}` desde `pass`/vault. El
|
||||
grupo nunca los hardcodea ni los persiste.
|
||||
|
||||
## Gotchas (seguridad — leer antes de usar)
|
||||
|
||||
- **El HAR es sensible**: contiene cookies y tokens en crudo. Trátalo como un secreto —
|
||||
gitignored, no subir a Gitea, no indexar, borrar tras destilar. El output de
|
||||
`har_extract_calls` también lleva esos valores hasta que los sustituyes por `{{param}}`.
|
||||
- **Secretos a `pass`/vault**, nunca en el código de la función-acción.
|
||||
- **Replay con efectos = peligroso**: reproducir un POST que reinicia, borra o paga es
|
||||
destructivo. La función-acción debe pedir confirmación o exponer un flag explícito
|
||||
(`--yes`/`confirm=True`) antes de disparar. Nunca replay ciego de una acción irreversible.
|
||||
- **HTTP puro no siempre reproduce**: token firmado en cliente, challenge JS, o WAF que
|
||||
exige fingerprint de navegador → cae a Nivel 2 (headless) o 3 (visible humanizado).
|
||||
- `http_replay_sequence` sigue redirects por defecto y `verify_tls=True`. La extracción
|
||||
JSON es dot-path simple (`a.b.0.c`), no JSONPath completo.
|
||||
|
||||
## Prerequisitos
|
||||
|
||||
- Fase 0 (grabar): grupo `web-proxy` operativo (mitmproxy + chromium). Ver su página.
|
||||
- Fase 1-2: `requests` en `python/.venv` (ya presente). Sin dependencias nuevas.
|
||||
Reference in New Issue
Block a user