chore: auto-commit (97 archivos)
- .claude/CLAUDE.md - .claude/agents/fn-recopilador/SKILL.md - .claude/rules/INDEX.md - .claude/rules/cpp_apps.md - bash/functions/infra/build_cpp_windows.sh - cpp/CMakeLists.txt - cpp/PATTERNS.md - cpp/framework/app_base.cpp - cpp/framework/app_base.h - dev/issues/README.md - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
---
|
||||
id: 0065
|
||||
title: Extraer jobs system de graph_explorer al registry (jobs_pool + cache + subprocess worker)
|
||||
status: pending
|
||||
priority: high
|
||||
created: 2026-05-09
|
||||
blocks: [0066]
|
||||
related: [0026, 0027, 0028]
|
||||
---
|
||||
|
||||
## Contexto
|
||||
|
||||
`projects/osint_graph/apps/graph_explorer/jobs.{cpp,h}` (1366 + 97 lineas) implementa:
|
||||
|
||||
- Pool de N `std::thread` workers leyendo cola de jobs en SQLite (tabla `jobs`).
|
||||
- Spawn de subprocess por job con wire protocol stdin (JSON ctx) / stderr (`PROGRESS:<float> <stage>`) / stdout (JSON resultado) / exit code.
|
||||
- Cache addressable `<app_dir>/cache/<sha256[0:2]>/<sha256>.{html,md,...}`.
|
||||
- Recovery: jobs que quedaron `running` de sesion anterior se marcan `error` al `jobs_init`.
|
||||
- `dirty_counter` que la UI lee para refrescar tras cambios.
|
||||
- Persistencia `JobRow` con created/started/finished/duration/progress/stage/error/result_json.
|
||||
|
||||
El proyecto `online_data_recopilation` (issue 0066) necesita el mismo sistema. En lugar de copy-paste, **extraer al registry** para que ambas apps importen.
|
||||
|
||||
## Plan de extraccion
|
||||
|
||||
1. **Identificar fronteras** entre logica generica (extraer) y especifica de graph_explorer (queda local):
|
||||
- Generico: thread pool, queue SQLite, subprocess spawn, wire protocol parser, cache sha256, recovery.
|
||||
- Especifico: aplicar `entities/relations/node_updates` al `operations.db` del grafo.
|
||||
|
||||
2. **Funciones nuevas del registry**:
|
||||
|
||||
| ID | Domain | Que hace |
|
||||
|---|---|---|
|
||||
| `jobs_pool_cpp_core` | core | Thread pool generico parametrizable (workers, callback `on_job(JobRow)`). Tabla `jobs` configurable de nombre. |
|
||||
| `subprocess_worker_cpp_infra` | infra | Spawn subprocess + capturar stdin/stderr/stdout con wire protocol (`PROGRESS:`, JSON final). Devuelve `WorkerResult{stdout_json, error, exit_code}`. |
|
||||
| `job_cache_sha256_cpp_infra` | infra | `cache_path(root, key) -> path`, `cache_put(root, key, bytes)`, `cache_get(root, key)`. Layout `<root>/<sha[0:2]>/<sha>`. |
|
||||
| `worker_manifest_loader_cpp_core` | core | Enumera `<dir>/<id>/manifest.yaml`, valida schema, devuelve `vector<WorkerManifest>`. |
|
||||
|
||||
3. **Tipos nuevos**:
|
||||
- `JobRow_cpp_core` — struct con campos comunes (id, worker_id, target_id, status, progress, stage, error, result_json, timestamps).
|
||||
- `WorkerManifest_cpp_core` — struct (id, name, description, applies_to, emits, params, uses_functions).
|
||||
- `WorkerResult_cpp_infra` — struct (stdout_json, stderr_log, exit_code, error).
|
||||
|
||||
4. **Migracion graph_explorer**:
|
||||
- Reemplazar `jobs.cpp/h` por imports al registry.
|
||||
- El callback `on_job` queda en `entity_ops.cpp` aplicando entities/relations.
|
||||
- Test: lanzar enricher `fetch_webpage`, verificar que sigue funcionando.
|
||||
|
||||
5. **Validacion**: `cd projects/osint_graph/apps/graph_explorer && cmake --build build` + tests existentes.
|
||||
|
||||
## Schema tabla `jobs` (generico)
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS jobs (
|
||||
id TEXT PRIMARY KEY,
|
||||
worker_id TEXT NOT NULL, -- antes "enricher_id"
|
||||
target_id TEXT NOT NULL, -- antes "node_id" (para odr es dataset_key, etc)
|
||||
target_label TEXT, -- antes "node_name"
|
||||
status TEXT NOT NULL, -- queued|running|done|error|cancelled
|
||||
progress REAL DEFAULT 0,
|
||||
stage TEXT,
|
||||
error TEXT,
|
||||
result_json TEXT,
|
||||
params_json TEXT, -- params del manifest serializados
|
||||
created_at INTEGER NOT NULL,
|
||||
started_at INTEGER,
|
||||
finished_at INTEGER
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS jobs_status_idx ON jobs(status);
|
||||
CREATE INDEX IF NOT EXISTS jobs_worker_idx ON jobs(worker_id);
|
||||
```
|
||||
|
||||
`graph_explorer` y `odr_console` comparten schema. Diferencia solo en interpretacion de `target_id`/`result_json` (callback per-app).
|
||||
|
||||
## Riesgos
|
||||
|
||||
- graph_explorer es app C++ activa con tests pasando. Romper imports = romper produccion.
|
||||
- Camino seguro: rama TBD `issue/0065-extract-jobs-to-registry` en sub-repo de graph_explorer + sub-repo de fn_registry. Mergear ambos cuando build verde.
|
||||
- Feature flag NO aplica (cambio de codigo sin runtime toggle posible).
|
||||
|
||||
## Criterios de aceptacion
|
||||
|
||||
- [ ] Funciones del registry creadas con tests + .md.
|
||||
- [ ] graph_explorer compila y pasa tests existentes (32 WSL + 21 Win).
|
||||
- [ ] `fetch_webpage` enricher funciona end-to-end en graph_explorer tras refactor.
|
||||
- [ ] odr_console (issue 0066) puede importar `jobs_pool_cpp_core` y lanzar 1 collector dummy.
|
||||
- [ ] Documentacion actualizada en `cpp/PATTERNS.md` mencionando jobs_pool como pieza estandar.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Migrar el sistema a Go (issue futura si vale la pena).
|
||||
- Cambiar wire protocol (ya estable, no romper enrichers existentes).
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
id: 0066
|
||||
title: online_data_recopilation — odr_console MVP (lanzador GUI + 5-pasos + 1 collector)
|
||||
status: pending
|
||||
priority: high
|
||||
created: 2026-05-09
|
||||
blocked_by: [0065]
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
|
||||
App C++ ImGui en `projects/online_data_recopilation/apps/odr_console/` que:
|
||||
|
||||
1. Lanza cualquier funcion/pipeline del registry desde panel GUI con form auto-generado (params_schema).
|
||||
2. Implementa el bucle reactivo de 5 pasos sobre `operations.db` propia.
|
||||
3. Reusa jobs system del registry (issue 0065) para concurrencia.
|
||||
4. Reusa enricher protocol + `cdp-cli` + funciones Python `fetch_webpage`/`web_search`/etc de osint_graph.
|
||||
|
||||
## Decisiones tomadas
|
||||
|
||||
| Tema | Decision |
|
||||
|---|---|
|
||||
| Workers default | 4 |
|
||||
| operations.db | Una unica por la app |
|
||||
| DuckDB | Embebido (linkar libduckdb) |
|
||||
| Collectors lang | Python primero; bash/go en futuras issues |
|
||||
| Browser | CDP via `cdp-cli` (issue 0038) |
|
||||
| Concurrencia | jobs_pool_cpp_core (issue 0065) |
|
||||
| TBD | Obligatorio (regla apps_tbd) — sub-repo `dataforge/odr_console` |
|
||||
|
||||
## Alcance MVP (este issue)
|
||||
|
||||
### Esqueleto codigo
|
||||
|
||||
- `main.cpp` — `fn::run_app` con AppConfig + render() + paneles.
|
||||
- `data_registry.cpp/h` — abre `registry.db` RO, expone `search(query)`, `get_function(id)`.
|
||||
- `data_operations.cpp/h` — abre `operations.db` RW, CRUD de relations/executions/entities/types_snapshot/assertions/assertion_results.
|
||||
- `data_duck.cpp/h` — abre `local_files/odr.duckdb`, `query(sql) -> rows`, `ingest_parquet(path, table)`.
|
||||
- `views_launcher.cpp/h` — panel busqueda FTS5 + lista resultados + form params + boton "Run" → encola job.
|
||||
- `views_jobs.cpp/h` — panel jobs queue (pendientes/running/done) + live progress.
|
||||
- `views_datasets.cpp/h` — panel DuckDB query editor + tabla preview.
|
||||
- `CMakeLists.txt` — `add_imgui_app(odr_console ...)` con SQLite, libduckdb, jobs_pool del registry.
|
||||
|
||||
### Migrations operations.db
|
||||
|
||||
`migrations/001_init.sql` — schema 5-pasos completo:
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS relations (...); -- pipelines diseñados
|
||||
CREATE TABLE IF NOT EXISTS executions (...); -- runs con metricas
|
||||
CREATE TABLE IF NOT EXISTS entities (...); -- datos recopilados
|
||||
CREATE TABLE IF NOT EXISTS types_snapshot (...); -- copia schema registry
|
||||
CREATE TABLE IF NOT EXISTS assertions (...); -- reglas SQL
|
||||
CREATE TABLE IF NOT EXISTS assertion_results (...); -- resultados eval
|
||||
```
|
||||
|
||||
Reusar schema de `fn_operations/migrations/` adaptado.
|
||||
|
||||
### Collector MVP: `api_hn_top`
|
||||
|
||||
`collectors/api_hn_top/`:
|
||||
- `manifest.yaml`: id, name, description, params (limit), uses_functions (`http_get_json_py_*`).
|
||||
- `run.py`: lee stdin JSON {ops_db_path, app_dir, registry_root, params}, fetcha HN top stories API, escribe parquet a `vault/raw/hn_top_<ts>.parquet`, inserta `entity` con `metadata.{path,row_count,checksum,source}`, emite `PROGRESS:` por stderr.
|
||||
|
||||
Verificacion end-to-end:
|
||||
1. Lanzar odr_console.
|
||||
2. Buscar "hn_top" en launcher → click Run.
|
||||
3. Job aparece en panel jobs, progress llega a 100.
|
||||
4. Entity en operations.db tabla `entities`.
|
||||
5. Parquet en `vaults/odr_data/raw/`.
|
||||
6. Datasets panel lo lista, query SQL devuelve filas.
|
||||
|
||||
## Out of scope MVP (issues futuras)
|
||||
|
||||
- Pipeline builder DAG (`imgui_node_editor`).
|
||||
- Assertions panel (eval --react).
|
||||
- Proposals inbox.
|
||||
- Browser CDP collectors (`browser_capture_dom`, `browser_login_capture`).
|
||||
- Watchlists / scheduling.
|
||||
- Rate limiting global.
|
||||
- Form auto-generador desde `params_schema` complejo (MVP: solo strings + ints).
|
||||
|
||||
## Criterios aceptacion
|
||||
|
||||
- [ ] App compila en WSL + Windows.
|
||||
- [ ] `app.md` indexado por `fn index` (aparece en `apps`).
|
||||
- [ ] Repo Gitea creado (`dataforge/odr_console`) y branch master sincronizado.
|
||||
- [ ] Collector `api_hn_top` recupera 30 stories, parquet escrito, entity creado.
|
||||
- [ ] Panel datasets ejecuta `SELECT count(*) FROM hn_top`.
|
||||
- [ ] Logs ImGui muestran `fn_log::log_info` calls del flujo.
|
||||
|
||||
## Riesgos
|
||||
|
||||
- Build C++ + DuckDB + SQLite + jobs_pool → CMake complejo. Vendoring limpio + apuntes en `cpp/PATTERNS.md`.
|
||||
- libduckdb en Windows: probar `duckdb.dll` junto al exe.
|
||||
- Collectors Python embebido (issue 0033 runtime) — MVP puede arrancar con `python3` del sistema; embeber despues.
|
||||
@@ -0,0 +1,168 @@
|
||||
---
|
||||
id: 0067
|
||||
title: Roadmap de prereqs — issues de osint_graph que odr_console necesita antes/durante MVP
|
||||
status: pending
|
||||
priority: high
|
||||
created: 2026-05-09
|
||||
related: [0065, 0066]
|
||||
references: [
|
||||
"projects/osint_graph/apps/graph_explorer/issues/0033-multilang-dispatcher-embedded-python.md",
|
||||
"projects/osint_graph/apps/graph_explorer/issues/0033c-fn-check-vendored.md",
|
||||
"projects/osint_graph/apps/graph_explorer/issues/0033d-indexer-python-runtime-fields.md",
|
||||
"projects/osint_graph/apps/graph_explorer/issues/0033e-compile-skill-orchestration.md",
|
||||
"projects/osint_graph/apps/graph_explorer/issues/0038-browser-launch-cdp-control.md",
|
||||
"projects/osint_graph/apps/graph_explorer/issues/0039-cookie-session-manager.md",
|
||||
"projects/osint_graph/apps/graph_explorer/issues/0040-multi-profile-management.md",
|
||||
"projects/osint_graph/apps/graph_explorer/issues/0029-enrichers-cdp.md",
|
||||
"projects/osint_graph/apps/graph_explorer/issues/0030-deep-enrich-macro.md",
|
||||
"projects/osint_graph/apps/graph_explorer/issues/0021-command-palette.md",
|
||||
"projects/osint_graph/apps/graph_explorer/issues/0034-port-system-enrichers-to-go.md",
|
||||
"projects/osint_graph/apps/graph_explorer/issues/0014-browser-extension.md",
|
||||
"projects/osint_graph/apps/graph_explorer/issues/0012-http-ingest-endpoint.md",
|
||||
"projects/osint_graph/apps/graph_explorer/issues/0017-gx-cli.md"
|
||||
]
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
|
||||
Documentar el orden de dependencias entre las issues de `graph_explorer` y los issues `0065` (extract jobs) + `0066` (odr_console MVP) para que ambas apps compartan infra (jobs system, runtime Python embebido, CDP browser, profiles, sessions) sin reescribir codigo. **Este issue NO implementa nada** — es el meta-plan que ordena en que orden se atacan las dependencias previas.
|
||||
|
||||
## Contexto
|
||||
|
||||
`odr_console` es la segunda app C++ ImGui que necesita el mismo stack de recoleccion de datos que `graph_explorer`:
|
||||
|
||||
- Workers concurrentes con subprocess + wire protocol stdin/stderr/stdout (jobs system, issue 0026 ya completado).
|
||||
- Python embebido portable (sin WSL) — issue 0033 pendiente.
|
||||
- Browser CDP con profiles + cookies — issues 0038/0039/0040 pendientes.
|
||||
- Compile skill que empaqueta runtime + vendored deps — issues 0033c/d/e pendientes.
|
||||
|
||||
Sin este orden:
|
||||
- `odr_console` arranca con dependencia WSL y se rompe en Windows nativo.
|
||||
- Los collectors browser-driven no funcionan hasta tener CDP.
|
||||
- Cada app duplicaria infra de jobs/cache/subprocess.
|
||||
|
||||
## Arquitectura
|
||||
|
||||
### Capas afectadas
|
||||
|
||||
| Capa | Estado actual | Que falta para odr |
|
||||
|---|---|---|
|
||||
| Registry C++ (`cpp/functions/`) | tiene `tokens`, `app_settings`, `app_about`, `logger`, `panel_menu`, etc. en `fn_framework` | añadir `jobs_pool`, `subprocess_worker`, `job_cache_sha256`, `worker_manifest_loader` (issue 0065) |
|
||||
| Registry Python (`python/functions/`) | tiene `fetch_webpage`, `web_search`, `extract_*`, `html_to_markdown`, `normalize_url` | reusar tal cual; vendor en collectors `_vendored/` |
|
||||
| Runtime Python embebido | NO existe (graph_explorer usa WSL) | issue 0033 — runtime portable Linux+Windows |
|
||||
| CDP browser control | NO existe | issues 0038/0039/0040 — `cdp-cli` Go binario + profiles + sessions |
|
||||
| Compile skill | builds `.exe` Windows + DLLs + assets | issue 0033e — empaqueta runtime + vendored + go binaries |
|
||||
|
||||
### Mapeo issues prereq → componente odr
|
||||
|
||||
| Issue graph_explorer | Componente odr afectado | Bloqueo? |
|
||||
|---|---|---|
|
||||
| 0033 (multilang + Python embebido) | runtime portable, sin WSL | **bloquea release Windows** |
|
||||
| 0033c (fn check vendored) | audit drift `_vendored/` ↔ registry | nice-to-have |
|
||||
| 0033d (indexer python_runtime fields) | `app.md` declara python_runtime | bloquea 0033e |
|
||||
| 0033e (compile skill orquesta) | distribuible self-contained | **bloquea release Windows** |
|
||||
| 0034 (port enrichers a Go) | acelera arranque de collectors | opcional |
|
||||
| 0038 (browser launch CDP) | collectors `browser_capture_dom`, `browser_login_capture` | bloquea browser collectors |
|
||||
| 0039 (cookie session manager) | collectors con auth | bloquea OSINT-style scraping |
|
||||
| 0040 (multi-profile management) | collectors paralelos por profile | bloquea multi-fuente |
|
||||
| 0029 (enrichers via CDP) | template para `fetch_webpage_browser` collector | nice-to-have |
|
||||
| 0030 (deep enrich macro) | patron para pipeline builder DAG | referencia, no bloquea |
|
||||
| 0021 (command palette Ctrl+K) | UX del launcher panel | nice-to-have |
|
||||
| 0014 (browser extension) | ingest desde browser → odr collectors | post-MVP |
|
||||
| 0012 (HTTP ingest endpoint) | endpoint compartido entre apps | post-MVP |
|
||||
| 0017 (gx CLI) | `odr` CLI espejo | post-MVP |
|
||||
|
||||
## Tareas
|
||||
|
||||
### Fase 1 — Bloqueantes para MVP odr (orden estricto)
|
||||
|
||||
- **1.1** Issue **0065** (extract jobs system to registry). Bloquea 0066. Refactor seguro: graph_explorer sigue funcionando.
|
||||
- **1.2** Issue **0033d** (indexer lee `python_runtime` fields). Pequeño, sin deps. Habilita 0033e.
|
||||
- **1.3** Issue **0033** (multilang dispatcher + Python embebido). Critico para Windows nativo. Sin esto, odr depende de WSL igual que graph_explorer hoy.
|
||||
- **1.4** Issue **0033e** (compile skill orquesta freeze + vendor + go builds). Permite que `/compile odr_console` produzca zip self-contained con runtime + collectors vendored.
|
||||
|
||||
### Fase 2 — MVP odr_console
|
||||
|
||||
- **2.1** Issue **0066** (odr_console MVP). Esqueleto + 1 collector `api_hn_top` end-to-end. Reusa 0065. NO depende de browser CDP (collector inicial es API JSON pura).
|
||||
- **2.2** Verificar build Windows + WSL. Compile skill copia exe + Python runtime + collectors a `Desktop/apps/odr_console/`.
|
||||
|
||||
### Fase 3 — Browser-driven collectors
|
||||
|
||||
- **3.1** Issue **0038** (browser launch + CDP control). graph_explorer lo necesita igual. odr lo consume por subprocess `cdp-cli` igual que graph_explorer.
|
||||
- **3.2** Issue **0039** (cookie session manager). Permite collectors con auth.
|
||||
- **3.3** Issue **0040** (multi-profile management). Permite N collectors en paralelo con profiles distintos.
|
||||
- **3.4** Crear collectors odr basados en CDP: `browser_capture_dom`, `browser_login_capture`, `browser_scroll_paginated` (issue futura).
|
||||
|
||||
### Fase 4 — Calidad y UX (post-MVP)
|
||||
|
||||
- **4.1** Issue **0033c** (fn check vendored). CI gate para drift detection.
|
||||
- **4.2** Issue **0034** (port enrichers a Go). Reduce dependencia Python opcional.
|
||||
- **4.3** Issue **0029** (enrichers via CDP — `fetch_webpage_browser`, `fetch_screenshot`). Templates aplicables como collectors.
|
||||
- **4.4** Issue **0021** (command palette Ctrl+K). UX comun a las dos apps; extraer al registry.
|
||||
- **4.5** Issue **0030** (deep enrich macro). Patron para pipeline builder DAG en odr.
|
||||
|
||||
### Fase 5 — Integraciones cross-app (largo plazo)
|
||||
|
||||
- **5.1** Issue **0012** (HTTP ingest endpoint local). Compartido por ambas apps.
|
||||
- **5.2** Issue **0017** (gx CLI). Crear `odr` CLI espejo o unificar bajo `gx` con subcomando.
|
||||
- **5.3** Issue **0014** (browser extension). Ingest desde browser apunta a 0012; ambas apps consumen.
|
||||
|
||||
## Ejemplo de uso
|
||||
|
||||
Roadmap visual del orden:
|
||||
|
||||
```
|
||||
[1.1 0065 extract jobs] ──┐
|
||||
[1.2 0033d indexer fields] ──┤── prereqs MVP odr
|
||||
[1.3 0033 multilang + python emb] ──┤ (sin estos, odr no compila distribuible)
|
||||
[1.4 0033e compile orquesta] ──┘
|
||||
↓
|
||||
[2.1 0066 odr MVP] ── MVP funcional con collector API
|
||||
[2.2 verify Windows+WSL]
|
||||
↓
|
||||
[3.1 0038 browser CDP] ──┐
|
||||
[3.2 0039 cookie manager] ──┤── browser-driven collectors
|
||||
[3.3 0040 multi-profile] ──┤
|
||||
[3.4 collectors browser] ──┘
|
||||
↓
|
||||
[4.x calidad: vendored audit, go ports, command palette, deep enrich]
|
||||
↓
|
||||
[5.x cross-app: HTTP endpoint, CLI unificado, extension]
|
||||
```
|
||||
|
||||
Bloqueo critico para "release Windows funcional": **1.1 → 1.2 → 1.3 → 1.4 → 2.1**.
|
||||
|
||||
## Decisiones de diseño
|
||||
|
||||
1. **Por que reordenar en lugar de bifurcar**: si odr clona jobs.cpp, divergira de graph_explorer en semanas. El registry-first justifica el coste de 0065 antes que 0066.
|
||||
|
||||
2. **Por que 0033 es critico antes que MVP**: graph_explorer hoy depende de WSL para correr enrichers en Windows. Si odr arranca igual, **dos apps con la misma deuda**. Mejor pagar 0033 una vez para ambas.
|
||||
|
||||
3. **Por que browser CDP no bloquea MVP**: el collector inicial `api_hn_top` es API JSON pura. Browser collectors son fase 3, una vez probado el flujo. Asi MVP llega a Windows en dias, no semanas.
|
||||
|
||||
4. **Por que NO portar enrichers a Go (0034) antes**: optimizacion prematura. Python embebido (0033) ya da portabilidad. Go solo si la latencia molesta.
|
||||
|
||||
5. **Por que command palette no es prereq**: UX nice-to-have. MVP launcher con search FTS5 + lista basta. 0021 se extrae al registry cuando ambas apps lo necesiten.
|
||||
|
||||
## Prerequisitos
|
||||
|
||||
- Issue 0026 (jobs system base) — completado.
|
||||
- Issue 0033b (vendor python functions) — completado.
|
||||
- `cpp/PATTERNS.md` y `cpp/DESIGN_SYSTEM.md` — ya autoritativas.
|
||||
- Regla `apps_tbd.md` — sub-repos Gitea + branch master + TBD activo.
|
||||
|
||||
## Riesgos
|
||||
|
||||
| Riesgo | Mitigacion |
|
||||
|---|---|
|
||||
| Issue 0033 (Python embebido) es grande, retrasa MVP odr semanas | Hacer 0066 con `python3` del sistema primero, migrar a embebido al cerrar 0033. Coste: dos releases — Linux/WSL primero, Windows nativo despues. |
|
||||
| Refactor 0065 rompe graph_explorer | TBD obligatorio en sub-repo de graph_explorer + tests pasando antes de mergear (32 WSL + 21 Win). |
|
||||
| Browser CDP (0038) se enreda con perfiles existentes del usuario | Issue 0040 establece profiles propios bajo `<app>/local_files/browser_profiles/<name>/`, no toca los del sistema. |
|
||||
| Compile skill (0033e) explota build matrix Linux+Windows+freeze+vendor | Trabajo incremental: primero `python_runtime: false` sigue funcionando como hoy; cuando 0033e este, opt-in. |
|
||||
| Drift entre `_vendored/` de graph_explorer y collectors de odr | 0033c (fn check vendored) gate en CI antes de mergear cambios en `python/functions/`. |
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Implementar ninguno de los issues referenciados — este meta-plan solo ordena.
|
||||
- Decidir si `gx` y `odr` se unifican bajo un CLI comun (ver fase 5).
|
||||
- Diseño detallado del pipeline builder DAG de odr (ver issue 0066).
|
||||
@@ -0,0 +1,176 @@
|
||||
---
|
||||
id: 0068
|
||||
title: Cerrar bucle reactivo — fn-analizador (fase 4) y fn-mejorador (fase 5) con contrato e2e_checks
|
||||
status: pending
|
||||
priority: high
|
||||
created: 2026-05-09
|
||||
related: [0026, 0027, 0028]
|
||||
---
|
||||
|
||||
## Contexto
|
||||
|
||||
El bucle reactivo del registry (CONSTRUIR → EJECUTAR → RECOPILAR → ANALIZAR → MEJORAR) tiene agentes para fases 1-3:
|
||||
|
||||
- **Fase 1 — CONSTRUIR**: `fn-constructor` (existe)
|
||||
- **Fase 2 — EJECUTAR**: `fn-executor` (existe)
|
||||
- **Fase 3 — RECOPILAR**: `fn-recopilador` (existe)
|
||||
- **Fase 4 — ANALIZAR**: falta agente
|
||||
- **Fase 5 — MEJORAR**: falta agente
|
||||
|
||||
Sin fases 4 y 5 el bucle no cierra. Cada app sigue requiriendo iteracion manual: el humano lanza, mira, decide si funciona, y propone fixes. Objetivo: que apps lleguen a master correctas sin esa iteracion manual.
|
||||
|
||||
## Objetivo
|
||||
|
||||
Disponer de un gate automatico pre-merge que valide end-to-end cualquier app del registry, y un mejorador que proponga cambios cuando la validacion falla. Capacidad reutilizable, no especifica de un proyecto.
|
||||
|
||||
## Diseno
|
||||
|
||||
### Contrato `e2e_checks` en `app.md`
|
||||
|
||||
Cada app declara su validacion end-to-end en el frontmatter:
|
||||
|
||||
```yaml
|
||||
e2e_checks:
|
||||
- id: build
|
||||
cmd: "cd frontend && pnpm build && cd .. && CGO_ENABLED=1 go build -tags fts5 -o kanban ."
|
||||
timeout_s: 120
|
||||
- id: smoke
|
||||
cmd: "./kanban --port 8095 --db /tmp/kanban_e2e.db &"
|
||||
health: "http://127.0.0.1:8095/api/board"
|
||||
timeout_s: 10
|
||||
- id: ops_audit
|
||||
ref: "fn-recopilador:apps/kanban"
|
||||
- id: migrations
|
||||
cmd: "sqlite3 /tmp/kanban_e2e.db 'SELECT version FROM schema_migrations;'"
|
||||
expect_exit: 0
|
||||
```
|
||||
|
||||
Tipos de check:
|
||||
- `cmd` — comando shell, exit 0 = OK.
|
||||
- `health` — espera `cmd` en background, hace GET y verifica 200.
|
||||
- `ref` — apunta a otro agente/funcion del registry (ej. `fn-recopilador`, `fn-doctor`).
|
||||
- `expect_exit`, `expect_stdout_contains`, `expect_stdout_json` — predicados sobre la salida.
|
||||
|
||||
### fn-analizador (fase 4)
|
||||
|
||||
Subagente nuevo. Input: `app_id`. Pasos:
|
||||
|
||||
1. Lee `e2e_checks` del `app.md`.
|
||||
2. Ejecuta cada check en orden, captura stdout/stderr/exit/duration.
|
||||
3. Eval assertions activas via `fn ops assertion eval --react`.
|
||||
4. Compara `executions.metrics` actual vs ventana historica (drift > umbral = warning).
|
||||
5. Diff golden outputs si app declara `tests/golden/`.
|
||||
6. Persiste resultado en nueva tabla `e2e_runs` de `operations.db`.
|
||||
7. Devuelve veredicto caveman:
|
||||
```
|
||||
build ✓ 42s
|
||||
smoke ✓ 0.8s
|
||||
ops_audit ✓
|
||||
assertion:R1 ✗ warning duration drift +47% vs p50
|
||||
```
|
||||
|
||||
Tools: Read, Bash, Grep, Glob. Escribe SOLO `assertion_results`, `entity.status`, `e2e_runs`. NO toca registry.db.
|
||||
|
||||
### fn-mejorador (fase 5)
|
||||
|
||||
Subagente nuevo. Input: salida de `fn-analizador` + `app_id`. Pasos:
|
||||
|
||||
1. Filtra fallos: `critical` → `kind=bug`, `warning` → `kind=optimization`.
|
||||
2. Por cada fallo, busca contexto en registry: funciones tocadas, ultimas N proposals.
|
||||
3. Crea proposal con `created_by=reactive_loop`, `evidence=[assertion_id, execution_id, e2e_run_id]`.
|
||||
4. Sugiere fix concreto (parametro, funcion a partir, refactor) — texto, NO codigo.
|
||||
5. Si fallo recurrente (>3 veces misma assertion) → `priority=high`.
|
||||
|
||||
Tools: Read, Bash, Grep. Escribe SOLO `proposals` en registry.db. Nunca modifica funciones.
|
||||
|
||||
### Skill `/validate-app <app_id>`
|
||||
|
||||
Orquesta cadena: `fn-executor` → `fn-recopilador` → `fn-analizador` → `fn-mejorador`. Devuelve tabla pass/fail + IDs de proposals creadas.
|
||||
|
||||
### Migracion `006_e2e_runs.sql`
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS e2e_runs (
|
||||
id TEXT PRIMARY KEY,
|
||||
app_id TEXT NOT NULL,
|
||||
started_at INTEGER NOT NULL,
|
||||
finished_at INTEGER,
|
||||
status TEXT NOT NULL, -- pass|fail|partial
|
||||
checks_total INTEGER NOT NULL,
|
||||
checks_pass INTEGER NOT NULL,
|
||||
checks_fail INTEGER NOT NULL,
|
||||
summary_json TEXT NOT NULL -- detalle por check
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS e2e_runs_app_idx ON e2e_runs(app_id, started_at DESC);
|
||||
```
|
||||
|
||||
### Funciones nuevas del registry
|
||||
|
||||
Delegables a `fn-constructor`:
|
||||
|
||||
| ID | Domain | Que hace |
|
||||
|---|---|---|
|
||||
| `e2e_run_checks_go_infra` | infra | Ejecuta lista de checks, devuelve `[]CheckResult` |
|
||||
| `golden_diff_go_core` | core | Compara archivo vs golden con umbral |
|
||||
| `metrics_drift_go_datascience` | datascience | p50/p95 historico vs actual |
|
||||
| `proposal_from_failure_go_infra` | infra | Formatea evidencia → proposal |
|
||||
| `health_probe_go_infra` | infra | GET con timeout, retry, codigo esperado |
|
||||
|
||||
Tipos:
|
||||
|
||||
| ID | Que |
|
||||
|---|---|
|
||||
| `E2ECheck_go_infra` | struct check (id, cmd, ref, health, expect_*) |
|
||||
| `CheckResult_go_infra` | struct resultado (id, status, duration_ms, stdout, stderr, exit) |
|
||||
|
||||
### fn-recopilador como diseñador de checks
|
||||
|
||||
`fn-recopilador` se extiende para **proponer e2e_checks por app** (modo design):
|
||||
|
||||
- Inspecciona `app.md` (lang, framework, entry_point, uses_functions).
|
||||
- Detecta patrones conocidos:
|
||||
- Go service con frontend Vite → propone build (pnpm + go), smoke (puerto + endpoint health).
|
||||
- C++ ImGui app → propone build (cmake), smoke (`--self-test` o lanzar y matar tras N segundos).
|
||||
- Python pipeline → propone run con args dummy y verificar exit 0.
|
||||
- Audita `operations.db` y deriva `ops_audit` automatico.
|
||||
- Escribe propuesta en `app.md` como bloque `e2e_checks_suggested:` para que humano apruebe → renombre a `e2e_checks:`.
|
||||
|
||||
Comando: `fn-recopilador design-e2e <app_id>`.
|
||||
|
||||
Asi `fn-analizador` recibe contratos completos de fabrica y solo necesita ejecutar.
|
||||
|
||||
## Plan de ejecucion
|
||||
|
||||
| Paso | Tarea | Estado |
|
||||
|---|---|---|
|
||||
| 1 | Contrato `e2e_checks` en `docs/templates/app.md` + 2 apps piloto (kanban, graph_explorer) | en curso |
|
||||
| 2 | Funciones registry: `e2e_run_checks`, `golden_diff`, `metrics_drift`, `proposal_from_failure`, `health_probe` | pendiente |
|
||||
| 3 | Migracion `006_e2e_runs.sql` en `fn_operations/migrations/` | pendiente |
|
||||
| 4 | Subagente `fn-analizador` + skill `/validate-app` | pendiente |
|
||||
| 5 | Extender `fn-recopilador` con modo `design-e2e` | pendiente |
|
||||
| 6 | Subagente `fn-mejorador` | pendiente |
|
||||
| 7 | Gate opcional en `/git-push` para apps con `e2e_checks` declarado | pendiente |
|
||||
|
||||
## Criterios de aceptacion
|
||||
|
||||
- [ ] Template `docs/templates/app.md` con seccion `e2e_checks` documentada.
|
||||
- [ ] `apps/kanban/app.md` declara `e2e_checks` (build + smoke + ops_audit + migrations).
|
||||
- [ ] `projects/osint_graph/apps/graph_explorer/app.md` declara `e2e_checks` (build + tests pytest + enricher smoke).
|
||||
- [ ] `fn-recopilador` puede sugerir `e2e_checks` para una app dada.
|
||||
- [ ] `fn-analizador` corre los checks y devuelve veredicto caveman.
|
||||
- [ ] `fn-mejorador` crea proposals con evidencia cuando hay fallos.
|
||||
- [ ] Skill `/validate-app <app_id>` orquesta la cadena completa.
|
||||
- [ ] Documentacion en `.claude/rules/` (nueva regla `e2e_validation.md`).
|
||||
|
||||
## Riesgos
|
||||
|
||||
- **Golden tests para C++/UI son caros**. Empezar build+smoke+assertions; goldens solo donde aporten (graph_explorer ya tiene capture system).
|
||||
- **Apps sin operations.db** (kanban usa `kanban.db` propia, no `operations.db`). El check `ops_audit` debe aceptar BD alternativa o saltarse.
|
||||
- **Smoke tests con puertos en uso**. Los pilotos deben usar puertos efimeros (`--port 0` o range alto) y BDs en `/tmp/`.
|
||||
- **Adopcion gradual**. Apps sin `e2e_checks` no se validan (y no bloquean merge). Visible en `fn doctor`.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Reemplazar `fn doctor` (que sigue siendo diagnostico read-only del estado).
|
||||
- Tests unitarios de funciones (siguen en `*_test.go`, `pytest`, etc.).
|
||||
- Performance benchmarks formales (los `metrics_drift` son aproximacion, no benchmark).
|
||||
@@ -0,0 +1,220 @@
|
||||
---
|
||||
id: 0069
|
||||
title: Bucle autonomo de subagentes — completar y mejorar tareas sin intervencion humana
|
||||
status: pending
|
||||
priority: medium
|
||||
created: 2026-05-09
|
||||
depends_on: [0068]
|
||||
related: [0026, 0027, 0028]
|
||||
---
|
||||
|
||||
## Contexto
|
||||
|
||||
El issue 0068 cierra el bucle reactivo a nivel **agentes individuales**:
|
||||
|
||||
- fn-1 `fn-constructor` — construye codigo
|
||||
- fn-2 `fn-executor` — ejecuta
|
||||
- fn-3 `fn-recopilador` — audita datos + diseña contrato e2e
|
||||
- fn-4 `fn-analizador` — valida end-to-end
|
||||
- fn-5 `fn-mejorador` — abre proposals con evidencia
|
||||
|
||||
Sin embargo, cada fase la **lanza un humano** (o el main thread bajo instruccion humana). El humano sigue siendo el orquestador. La promesa real es:
|
||||
|
||||
> "Lanzar una tarea al sistema, irse, y volver para encontrarla terminada y mejorada."
|
||||
|
||||
Esa promesa requiere un **orquestador autonomo** que recorra el bucle CONSTRUIR → EJECUTAR → RECOPILAR → ANALIZAR → MEJORAR sin intervencion humana, hasta convergencia (suite verde) o tope de iteraciones / tiempo.
|
||||
|
||||
Este issue planifica ese orquestador.
|
||||
|
||||
## Objetivo
|
||||
|
||||
Disponer de un **runner autonomo** que toma una tarea (issue, feature, app skeleton) y la entrega **funcional, validada y con proposals para mejoras** sin intervencion humana entre fases. El humano solo:
|
||||
|
||||
1. Define el objetivo (issue file).
|
||||
2. Recibe el resultado al final (PR draft, run_ids verdes, proposals creadas).
|
||||
|
||||
Si el bucle no converge en N iteraciones o T tiempo, se para y reporta el estado al humano para decision.
|
||||
|
||||
## Diseno
|
||||
|
||||
### Componente nuevo: `fn-orquestador`
|
||||
|
||||
Subagente meta-orquestador. Input: `issue_id` o `task_spec`. Algoritmo:
|
||||
|
||||
```
|
||||
1. Leer task_spec (issue file: objetivo, criterios de aceptacion, fase actual)
|
||||
2. Loop hasta convergencia o limite:
|
||||
a. Determinar siguiente fase pendiente (CONSTRUIR/EJECUTAR/RECOPILAR/ANALIZAR/MEJORAR)
|
||||
b. Despachar al subagente correspondiente con prompt derivado del task_spec
|
||||
c. Capturar output del subagente
|
||||
d. Persistir progreso en task_runs (nueva tabla)
|
||||
e. Si fase = ANALIZAR y status = pass:
|
||||
- Aplicar fixes propuestos por MEJORAR (con limite de auto-apply, ver §Garantías)
|
||||
- Repetir desde CONSTRUIR si todavia hay criterios sin cumplir
|
||||
f. Si fase = ANALIZAR y status = fail:
|
||||
- Despachar a MEJORAR
|
||||
- Aplicar 1-2 proposals automaticas (solo si pasan filtros de seguridad, ver §Garantías)
|
||||
- Volver a CONSTRUIR/EJECUTAR para validar
|
||||
g. Si N iteraciones sin progreso → parar, reportar estado, pedir humano
|
||||
3. Reportar resultado final: estado tarea, run_ids, proposals creadas, PR draft si aplica
|
||||
```
|
||||
|
||||
### Nueva tabla `task_runs` en operations.db
|
||||
|
||||
```sql
|
||||
CREATE TABLE task_runs (
|
||||
id TEXT PRIMARY KEY,
|
||||
task_id TEXT NOT NULL, -- issue_id o slug
|
||||
started_at INTEGER NOT NULL,
|
||||
finished_at INTEGER,
|
||||
status TEXT NOT NULL, -- running|converged|stalled|aborted
|
||||
iterations INTEGER NOT NULL DEFAULT 0,
|
||||
last_phase TEXT, -- construir|ejecutar|recopilar|analizar|mejorar
|
||||
last_run_id TEXT, -- e2e_runs.id de la ultima validacion
|
||||
progress_json TEXT NOT NULL DEFAULT '[]' -- log de fases con timestamps
|
||||
);
|
||||
```
|
||||
|
||||
### Skill `/autonomous-task <issue_id>`
|
||||
|
||||
Lanza el `fn-orquestador` con limites configurables:
|
||||
|
||||
```
|
||||
/autonomous-task 0070 --max-iterations 10 --max-minutes 60 --auto-apply-proposals safe
|
||||
```
|
||||
|
||||
Flags:
|
||||
- `--max-iterations N`: tope de iteraciones del bucle (default 10).
|
||||
- `--max-minutes M`: timeout total (default 60).
|
||||
- `--auto-apply-proposals`: nivel de autonomia para aplicar proposals:
|
||||
- `none`: solo crea proposals, nunca aplica codigo.
|
||||
- `safe`: aplica proposals con `kind=improve_function` y diff < 50 lineas.
|
||||
- `aggressive`: aplica casi todas salvo las marcadas `risk=high`.
|
||||
- `--branch <name>`: rama TBD donde trabaja el bucle (default `auto/<issue_id>`).
|
||||
- `--dry-run`: no aplica nada, solo simula y reporta plan.
|
||||
|
||||
### Garantias de seguridad
|
||||
|
||||
El bucle autonomo es peligroso si el agente:
|
||||
- Borra archivos importantes.
|
||||
- Bypasea tests.
|
||||
- Toca produccion.
|
||||
- Mergea codigo roto a master.
|
||||
|
||||
Reglas obligatorias:
|
||||
|
||||
1. **Sandbox de rama**. El orquestador SIEMPRE trabaja en rama `auto/<issue>`, nunca master.
|
||||
2. **No `--no-verify`, no `git push --force`**. Hooks de pre-commit del repo se respetan.
|
||||
3. **No mergea a master**. Genera PR draft. Humano aprueba el merge.
|
||||
4. **No toca `.claude/`, `dev/issues/` salvo el del task** ni archivos `.env`/secrets. Lista de paths protegidos en `dev/autonomous_protected_paths.json`.
|
||||
5. **Filtro de proposals auto-aplicables**:
|
||||
- Solo proposals creadas por `fn-mejorador` con `evidence` que apunte a runs reales.
|
||||
- Diff < 50 lineas (configurable).
|
||||
- No tocan tests existentes (no se "arreglan" los tests).
|
||||
- No introducen dependencias nuevas (`pnpm add`, `go get`, etc).
|
||||
6. **Watchdog de progreso**. Si 2 iteraciones consecutivas dan el mismo set de fails, parar y pedir humano (loop infinito detectado).
|
||||
7. **Auditoria completa**. Cada decision del orquestador se loggea en `task_runs.progress_json` con razonamiento + diff aplicado.
|
||||
8. **Rollback trivial**. La rama es desechable; si la suite no converge, humano puede `git branch -D auto/<issue>` y empezar de nuevo.
|
||||
|
||||
### Tipos de tareas soportadas
|
||||
|
||||
Empezar con un subset acotado:
|
||||
|
||||
| Tipo | Descripcion | Convergencia |
|
||||
|---|---|---|
|
||||
| `feature_app_simple` | Endpoint nuevo + handler + test | suite verde + endpoint responde 200 |
|
||||
| `bugfix_with_repro` | Issue con repro reproducible | repro pasa de fail a pass |
|
||||
| `refactor_safe` | Renombrar/extraer funcion + actualizar callers | suite igual de verde + grep limpio |
|
||||
| `add_e2e_check` | Crear `e2e_checks` para app sin ellos via fn-recopilador | app tiene contrato + run pasa |
|
||||
|
||||
NO soportadas inicialmente (requieren mas heuristica):
|
||||
- Diseño de arquitectura nuevo.
|
||||
- Decisiones de UX subjetivas.
|
||||
- Cambios en BD productiva.
|
||||
- Cualquier cosa que toque secrets/credenciales.
|
||||
|
||||
### Convergencia
|
||||
|
||||
El bucle termina cuando:
|
||||
- **Convergido**: todos los criterios de aceptacion del issue marcan ✓ Y la suite e2e pasa Y `fn doctor <app>` pasa.
|
||||
- **Estancado**: misma metric de fallos en 2+ iteraciones (loop sin progreso).
|
||||
- **Timeout**: `--max-minutes` alcanzado.
|
||||
- **Iteraciones**: `--max-iterations` alcanzado.
|
||||
- **Bloqueo humano**: el orquestador detecta una decision que requiere humano (ej. eleccion de libreria nueva, schema breaking change) y para con `status=needs_human`.
|
||||
|
||||
En cualquier caso, output:
|
||||
|
||||
```
|
||||
=== /autonomous-task: <issue_id> ===
|
||||
status: <converged|stalled|timeout|needs_human>
|
||||
iterations: N / max
|
||||
duration: M min / max
|
||||
branch: auto/<issue>
|
||||
PR draft: <url o "no creado">
|
||||
proposals: <count> creadas, <count> aplicadas
|
||||
last run_id: <run_id> (status: pass|fail)
|
||||
|
||||
Detalle de iteraciones:
|
||||
1. construir → ok (3 funciones nuevas)
|
||||
2. ejecutar → ok
|
||||
3. analizar → fail (3 checks)
|
||||
4. mejorar → 3 proposals (2 auto-aplicadas)
|
||||
5. construir → ok (re-build tras patches)
|
||||
6. analizar → pass
|
||||
7. recopilador → ok (operations.db integra)
|
||||
8. CONVERGED
|
||||
|
||||
Siguientes pasos para humano:
|
||||
- Revisar PR draft <url>
|
||||
- fn proposal list -s pending --target-id <issue>
|
||||
```
|
||||
|
||||
## Plan de ejecucion
|
||||
|
||||
| Paso | Tarea | Dependencia |
|
||||
|---|---|---|
|
||||
| 1 | Migracion `006_task_runs.sql` en `fn_operations/migrations/` | issue 0068 cerrado |
|
||||
| 2 | Subagente `fn-orquestador` (.claude/agents/fn-orquestador/SKILL.md) | paso 1 |
|
||||
| 3 | Lista de paths protegidos (`dev/autonomous_protected_paths.json`) | paso 2 |
|
||||
| 4 | Skill `/autonomous-task <issue_id>` (.claude/commands/autonomous-task.md) | paso 2 |
|
||||
| 5 | Funciones registry: `task_run_persist_go_infra`, `proposal_filter_safe_go_infra`, `git_branch_sandbox_go_infra`, `pr_draft_create_go_infra` | paso 2 |
|
||||
| 6 | Tipo `TaskSpec_go_core` (issue + criterios + limites) | paso 5 |
|
||||
| 7 | Pilotaje en 1 issue tipo `feature_app_simple` (ej. añadir endpoint trivial a kanban) | paso 4 |
|
||||
| 8 | Pilotaje en 1 issue tipo `add_e2e_check` (correr orquestador para añadir contrato a app sin el) | paso 7 |
|
||||
| 9 | Hardening: tests del orquestador, edge cases (red flaky, BD locked, conflicto merge) | paso 8 |
|
||||
| 10 | Documentacion + regla `.claude/rules/autonomous_loop.md` | paso 9 |
|
||||
|
||||
## Criterios de aceptacion
|
||||
|
||||
- [ ] `fn-orquestador` definido como subagente, model haiku-4-5 o sonnet-4-6 (probar ambos).
|
||||
- [ ] Tabla `task_runs` migrada con migration aditiva, sin romper apps existentes.
|
||||
- [ ] Skill `/autonomous-task` orquesta los 5 subagentes en bucle.
|
||||
- [ ] Filtro de proposals auto-aplicables documentado y testeado contra dataset adverso.
|
||||
- [ ] Pilotaje exitoso en 2 issues distintas: feature_app_simple + add_e2e_check.
|
||||
- [ ] Watchdog de "no progreso" detiene loops en pruebas con tareas imposibles.
|
||||
- [ ] Output del runner incluye trazabilidad completa (cada decision + diff aplicado).
|
||||
- [ ] Documentacion en `.claude/rules/autonomous_loop.md`.
|
||||
|
||||
## Riesgos
|
||||
|
||||
- **Loops infinitos**: agentes que "parchean" tests rotos en vez de codigo. Mitigacion: filtro de proposals (no tocar tests), watchdog.
|
||||
- **Coste**: cada iteracion = N llamadas a Claude. Mitigacion: `--max-iterations`, `--max-minutes`, modelos mas baratos para fases mecanicas (haiku para `fn-recopilador`, sonnet para `fn-constructor`).
|
||||
- **Calidad**: codigo auto-generado puede compilar pero ser malo. Mitigacion: `fn-analizador` valida no solo build sino assertions + drift; humano siempre revisa PR.
|
||||
- **Seguridad**: agente comprometiendo el repo. Mitigacion: sandbox de rama, paths protegidos, no merge automatico, hooks no skipeables.
|
||||
- **Drift de criterios**: el agente "interpreta" liberamente los criterios de aceptacion del issue. Mitigacion: criterios en el issue deben ser verificables programaticamente (ej. "endpoint responde 200" mejor que "el endpoint funciona bien").
|
||||
- **Acumulacion de proposals**: si el bucle crea muchas proposals sin que humano las cierre, ruido. Mitigacion: limite por task_run, dedup automatica por similitud.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Auto-merge a master (siempre PR draft).
|
||||
- Toma de decisiones de arquitectura (eleccion de libreria, patron de diseño).
|
||||
- Tareas que requieran credenciales (deploys, llamadas a APIs externas con auth).
|
||||
- Tareas que toquen schema de DBs productivas.
|
||||
- Self-modification del orquestador (no se puede mejorar a si mismo en el mismo run).
|
||||
|
||||
## Notas
|
||||
|
||||
- Inspiracion: SWE-bench, agentic flows tipo aider/cursor compose, Devin. Diferencia: aqui el agente NO escribe codigo libre — orquesta agentes especializados que ya respetan las reglas del registry.
|
||||
- El bucle reactivo del CLAUDE.md ya describe semantica de fases. Este issue solo añade el **orquestador** que las recorre solo.
|
||||
- La regla `kiss.md` aplica: empezar con tipos de tarea simples y verificables. Resistir tentacion de soportar todo desde dia 1.
|
||||
- Conexion con `feature_flags.md`: si el bucle queda detras de un flag (`autonomous_loop_enabled`), se puede activar/desactivar sin redeploy.
|
||||
@@ -0,0 +1,140 @@
|
||||
---
|
||||
id: 0070
|
||||
title: Funciones globales del registry para control de navegador (find by text, click by text, scroll, HAR, jsonld, opengraph, ...)
|
||||
status: pending
|
||||
priority: medium
|
||||
created: 2026-05-09
|
||||
related_apps: [navegator_dashboard, graph_explorer]
|
||||
related_issues_app: [navegator/0001, graph_explorer/0038]
|
||||
---
|
||||
|
||||
## Contexto
|
||||
|
||||
`functions/browser/` (Go) tiene hoy 12 primitivas CDP de bajo nivel: `cdp_connect`, `cdp_navigate`, `cdp_evaluate`, `cdp_get_html`, `cdp_screenshot`, `cdp_click` (por selector CSS), `cdp_type_text`, `cdp_wait_load`, `cdp_wait_element`, `cdp_set_cookie`, `cdp_close`, `chrome_launch`. Todas reutilizables, todas testeadas.
|
||||
|
||||
Estas primitivas son suficientes para muchos casos pero **siguen siendo bajo nivel**: el consumidor (cdp-cli, navegator_dashboard, agentes) tiene que componer manualmente patrones que se repiten una y otra vez. Falta una capa intermedia de funciones de mas alto nivel que **resuelvan tareas reales** sin que cada caller las re-componga.
|
||||
|
||||
## Objetivo
|
||||
|
||||
Ampliar `functions/browser/` (Go preferentemente, Python cuando aplique) con primitivas componibles que resuelvan los patrones recurrentes:
|
||||
|
||||
1. **Localizacion robusta de elementos**: por texto visible, por XPath, por aria-label.
|
||||
2. **Acciones combinadas**: click por texto, fill form, submit, scroll-to, wait-navigation.
|
||||
3. **Captura estructurada**: HAR, jsonld, opengraph, meta tags, schema.org.
|
||||
4. **Navegacion segura**: navegacion + wait + retry + screenshot diff.
|
||||
5. **Multi-tab / multi-instance**: enumerar tabs de N instancias, copiar cookie entre profiles.
|
||||
|
||||
Cualquier app del registry que controle browsers (navegator_dashboard, cdp-cli, graph_explorer, futuras) consume esta capa en vez de reimplementar.
|
||||
|
||||
## Funciones propuestas (lista inicial)
|
||||
|
||||
Todas en `functions/browser/`. Lenguaje preferido entre parentesis. Pureza siempre `impure` (todas tocan red/IO).
|
||||
|
||||
### Localizacion / queries
|
||||
|
||||
| ID | Que hace |
|
||||
|---|---|
|
||||
| `cdp_find_by_text_go_browser` | Devuelve selector CSS unico del primer elemento cuyo `innerText` contiene un texto dado. Filtros: `tag`, `case_sensitive`, `exact`. |
|
||||
| `cdp_find_all_by_text_go_browser` | Como el anterior pero retorna lista de selectores. |
|
||||
| `cdp_find_by_xpath_go_browser` | Equivalente con XPath. |
|
||||
| `cdp_find_by_aria_go_browser` | Por `aria-label` o `role`. Util en SPAs accesibles. |
|
||||
| `cdp_get_attribute_go_browser` | `<selector>.getAttribute(name)`. |
|
||||
| `cdp_count_elements_go_browser` | `document.querySelectorAll(sel).length`. |
|
||||
|
||||
### Acciones
|
||||
|
||||
| ID | Que hace |
|
||||
|---|---|
|
||||
| `cdp_click_text_go_browser` | `find_by_text` + `click`. Errores claros si no encuentra. |
|
||||
| `cdp_fill_form_go_browser` | Recibe `map[selector]value`, hace click + type por cada uno. |
|
||||
| `cdp_submit_form_go_browser` | Click en boton submit + `wait_navigation`. |
|
||||
| `cdp_scroll_to_go_browser` | `selector.scrollIntoView({block:'center'})` + verifica que esta en viewport. |
|
||||
| `cdp_press_key_go_browser` | `Input.dispatchKeyEvent` con tecla nombrada (Enter, Tab, Escape, ArrowDown). |
|
||||
| `cdp_hover_go_browser` | `Input.dispatchMouseEvent` mouseMoved sobre el elemento. |
|
||||
|
||||
### Esperas robustas
|
||||
|
||||
| ID | Que hace |
|
||||
|---|---|
|
||||
| `cdp_wait_navigation_go_browser` | Espera `Page.frameNavigated` + `Page.loadEventFired` con timeout. |
|
||||
| `cdp_wait_text_go_browser` | Espera a que aparezca un texto en cualquier sitio del DOM. |
|
||||
| `cdp_wait_url_go_browser` | Espera a que `location.href` matchee un regex. |
|
||||
| `cdp_wait_idle_go_browser` | Espera a que la red este idle N ms (Network.* events). |
|
||||
|
||||
### Captura estructurada
|
||||
|
||||
| ID | Que hace |
|
||||
|---|---|
|
||||
| `cdp_har_record_go_browser` | Subscribe `Network.*` durante una accion, retorna HAR JSON estandar. |
|
||||
| `extract_jsonld_py_browser` | Parse `<script type="application/ld+json">` del HTML. |
|
||||
| `extract_opengraph_py_browser` | Parse `<meta property="og:*">`. |
|
||||
| `extract_meta_basic_py_browser` | Title, description, canonical, lang, charset. |
|
||||
| `extract_schema_org_py_browser` | Microdata `itemtype="https://schema.org/..."`. |
|
||||
| `extract_forms_py_browser` | Lista forms del HTML con campos, action, method. |
|
||||
| `cdp_dump_cookies_go_browser` | `Network.getAllCookies` → JSON. |
|
||||
| `cdp_screenshot_element_go_browser` | Screenshot recortado al bounding box del selector. |
|
||||
|
||||
### Multi-tab / multi-instance
|
||||
|
||||
| ID | Que hace |
|
||||
|---|---|
|
||||
| `cdp_list_tabs_go_browser` | GET `/json` → lista parseada de tabs. |
|
||||
| `cdp_focus_tab_go_browser` | POST `/json/activate/{id}`. |
|
||||
| `cdp_close_tab_go_browser` | POST `/json/close/{id}`. |
|
||||
| `cdp_new_tab_go_browser` | POST `/json/new?url=...`. |
|
||||
| `cdp_copy_cookies_go_browser` | Lee cookies de un profile, las pone en otro (ambos via CDP). |
|
||||
|
||||
### Composiciones (`pipelines`)
|
||||
|
||||
| ID | Que hace |
|
||||
|---|---|
|
||||
| `browser_login_form_pipeline` | navigate + wait + fill_form + submit + wait_navigation + dump_cookies. Util para pre-logins en perfiles aislados. |
|
||||
| `browser_screenshot_diff_pipeline` | navigate + screenshot + comparar contra golden + reportar. |
|
||||
| `crawl_seeded_pipeline` | navigate seeds + extract links + push a queue + dedup + extract elegido. |
|
||||
|
||||
## Criterios de calidad para añadir una funcion
|
||||
|
||||
Antes de delegar a `fn-constructor`:
|
||||
|
||||
- **Patron real recurrente**, no especulativo. Si solo lo usa un caller hoy, esperar.
|
||||
- **API simple**: max 5 parametros con valores por defecto sensatos.
|
||||
- **Tests obligatorios** contra Chrome local (env-gated, no CI default — ver `cdp_*_test.go` actuales).
|
||||
- **Documentacion `.md`** con ejemplo invocacion + caso de uso real (que app/agente la consume).
|
||||
- **Sin estado global**: cada llamada recibe `*CDPConn`, no asume singleton.
|
||||
|
||||
## Estrategia de adopcion
|
||||
|
||||
Por **demanda**, no anticipado:
|
||||
|
||||
1. Cuando una capa del dashboard (navegator/0001) o un enricher de graph_explorer requiera componer un patron, primero buscar si ya existe en el registry.
|
||||
2. Si no existe y se usa **dos veces o aparece en TODO**, abrir sub-issue de este 0070 con la firma propuesta.
|
||||
3. Delegar a `fn-constructor` con los criterios de arriba.
|
||||
4. Migrar a la nueva funcion el caller que la pidio + cualquier otro que estuviera reimplementando lo mismo.
|
||||
|
||||
No precrear todas a la vez — riesgo de funciones zombies que nadie usa.
|
||||
|
||||
## Sub-issues iniciales (los que el dashboard v2 va a pedir)
|
||||
|
||||
- `0070a` — `cdp_find_by_text_go_browser` + `cdp_click_text_go_browser`. Bloquea Tab Detail y Recipes.
|
||||
- `0070b` — `cdp_har_record_go_browser`. Bloquea Network panel.
|
||||
- `0070c` — `extract_jsonld_py_browser` + `extract_opengraph_py_browser`. Bloquea `/extract/structured`.
|
||||
- `0070d` — `cdp_list_tabs_go_browser` + `cdp_new_tab_go_browser`. Bloquea Tabs panel del dashboard.
|
||||
|
||||
Resto se abren cuando se necesiten.
|
||||
|
||||
## Relacion con `cdp-cli`
|
||||
|
||||
Cuando una funcion nueva se añade al registry, `cdp-cli` (`projects/osint_graph/apps/graph_explorer/cdp-cli/`) gana un subcomando que la envuelve. Asi tanto el dashboard (in-process) como agentes/scripts (subprocess) tienen acceso. Patron ya establecido con las 10 funciones actuales.
|
||||
|
||||
## Riesgos
|
||||
|
||||
| Riesgo | Mitigacion |
|
||||
|---|---|
|
||||
| Funciones zombies si las pre-creamos | Solo crear cuando hay 2 callers o demanda real. |
|
||||
| Fragmentacion: tener 50 funciones de queries similares | Revision de overlap antes de delegar a fn-constructor. Preferir parametros sobre nuevas funciones. |
|
||||
| Tests dependen de Chrome local — flakiness en CI | Tag `slow` + env-gate. CI nocturno opcional. |
|
||||
| Diferencias entre Chrome versions (selectores cambian, eventos rebrandean) | Tests cubren la API CDP estable, no el DOM de sitios externos. |
|
||||
|
||||
## Definicion de hecho
|
||||
|
||||
Cuando navegator_dashboard v3 cierre, las funciones invocadas por sus endpoints `/extract/*`, `/crawl`, panel Network, panel Tabs y panel Tab Detail viven todas en `functions/browser/` o `python/functions/browser/` (segun lenguaje), no inline en el dashboard. El dashboard es 100% orquestador.
|
||||
@@ -80,3 +80,6 @@
|
||||
| [0062](0062-deprecate-unused-core-functions.md) | Politica de deprecacion para funciones del registry sin consumidores | pendiente | baja | research | — |
|
||||
| [0063](0063-kanban-stickers.md) | kanban: sistema de stickers (emojis) sobre cards | pendiente | media | feature | — |
|
||||
| [0064](completed/0064-registry-mcp-server.md) | registry_mcp: servidor MCP que expone registry.db a Claude | completado | alta | feature | — |
|
||||
| [0065](0065-extract-jobs-system-to-registry.md) | Extraer jobs system de graph_explorer al registry (jobs_pool + cache + subprocess worker) | pendiente | alta | refactor | 0066 |
|
||||
| [0066](0066-online-data-recopilation-mvp.md) | online_data_recopilation — odr_console MVP (lanzador GUI + 5-pasos + 1 collector) | pendiente | alta | feature | — |
|
||||
| [0067](0067-odr-osint-prereqs-roadmap.md) | Roadmap de prereqs — issues de osint_graph que odr_console necesita antes/durante MVP | pendiente | alta | planning | — |
|
||||
|
||||
Reference in New Issue
Block a user