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:
2026-05-09 18:11:24 +02:00
parent 852322a708
commit 750b7abcd5
99 changed files with 7879 additions and 73 deletions
@@ -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.
+3
View File
@@ -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 | — |