docs(issues): add 0071a chat, 0071b jobs, 0071g app_db_init extraction plans
Sub-issues activables de 0071 con plan concreto: API, dependencias, migracion, tests, anti-patrones. - 0071a (alta): claude_chat_panel — 2 consumidores reales (graph_explorer + navegator_dashboard, ~2500 LoC dup). Depende de 0071f. - 0071b (media): jobs_queue_panel — absorbe issue 0065. Depende de 0071f. Pre-requisito: auditar dup vs odr_console. - 0071g (media): app_db_init Tier 4 — 4+ duplicaciones en graph_explorer. Bajo riesgo. README actualizado. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,127 @@
|
|||||||
|
---
|
||||||
|
id: 0071a
|
||||||
|
title: Extraer `claude_chat_panel` a cpp/functions/core/ (sub-issue de 0071)
|
||||||
|
status: pending
|
||||||
|
priority: alta
|
||||||
|
created: 2026-05-10
|
||||||
|
parent: 0071
|
||||||
|
related_apps: [graph_explorer, navegator_dashboard]
|
||||||
|
depends_on: [0071f]
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contexto
|
||||||
|
|
||||||
|
Sub-issue derivado de 0071. **Rule of three cumplida hoy:** existe duplicacion masiva del panel de chat con `claude -p`:
|
||||||
|
|
||||||
|
| Consumidor | Archivos | LoC | Estado |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `projects/osint_graph/apps/graph_explorer/chat.{cpp,h}` | 2 | 1241 + ~80 | Original |
|
||||||
|
| `projects/navegator/apps/navegator_dashboard/chat.{cpp,h}` | 2 | 1252 + ~80 | Copy+adapt reciente |
|
||||||
|
|
||||||
|
~2500 LoC duplicados con divergencia minima (env vars, CLI tool name, mutations counter). Bug fixes hay que aplicarlos en ambos. 3er consumidor potencial: `kanban` (agente para cards), `registry_dashboard` (agente para proposals).
|
||||||
|
|
||||||
|
## Objetivo
|
||||||
|
|
||||||
|
Funcion `claude_chat_panel` en `cpp/functions/core/` que encapsule:
|
||||||
|
- Spawn de `claude -p --dangerously-skip-permissions` (via `subprocess_streamer` de 0071f)
|
||||||
|
- Parser stream-json line-by-line (turn/role/tool_use/content)
|
||||||
|
- Render historial ImGui con bubbles user/assistant + tool_use detectado
|
||||||
|
- Input multi-linea con `Ctrl+Enter` send + history (flecha arriba/abajo)
|
||||||
|
- Persistencia opcional de conversacion en SQLite local
|
||||||
|
- Callback de mutations counter (la app recarga su BD cuando el agente la modifica)
|
||||||
|
|
||||||
|
## Dependencia previa
|
||||||
|
|
||||||
|
**0071f** (`subprocess_streamer`) DEBE estar mergeado. El chat_panel lo usa internamente. Sin ese building block, este issue no se aborda — se duplicaria la logica de spawn/pipes una vez mas.
|
||||||
|
|
||||||
|
## API propuesta
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace fn_core {
|
||||||
|
|
||||||
|
struct ClaudeChatConfig {
|
||||||
|
// Binario claude (default: "claude" en PATH; en WSL puede ser path absoluto a Windows).
|
||||||
|
std::string claude_bin = "claude";
|
||||||
|
|
||||||
|
// CLI helper que el agente invoca (ej. "gx-cli", "cdp-cli", "kanban-cli").
|
||||||
|
std::string cli_tool_name;
|
||||||
|
std::string cli_tool_dir; // dir donde vive el binario CLI helper
|
||||||
|
|
||||||
|
// Variables de entorno que el subproceso hereda (ej. GX_OPS_DB, NAVD_PROFILE_DIR).
|
||||||
|
std::map<std::string, std::string> env_vars;
|
||||||
|
|
||||||
|
// Path del .mcp.json que se le pasa a claude --mcp-config.
|
||||||
|
// Si vacio, no se pasa flag (usa el default del proyecto).
|
||||||
|
std::string mcp_config_path;
|
||||||
|
|
||||||
|
// Prompt sistema opcional (claude -p ... --append-system-prompt "...").
|
||||||
|
std::string system_prompt;
|
||||||
|
|
||||||
|
// Callback que la app implementa: devuelve N de mutaciones desde la ultima vez.
|
||||||
|
// El panel lo usa para mostrar "agent modificado N entities, recargar?" boton.
|
||||||
|
std::function<int()> mutations_counter;
|
||||||
|
|
||||||
|
// Path para persistencia local del historial (SQLite). Vacio = sin persistencia.
|
||||||
|
std::string history_db_path;
|
||||||
|
|
||||||
|
// Path de log de stream-json crudo (debug). Vacio = sin log.
|
||||||
|
std::string log_file_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChatHandle; // opaco
|
||||||
|
|
||||||
|
ChatHandle* chat_create(const ClaudeChatConfig& cfg);
|
||||||
|
void chat_send(ChatHandle*, const char* user_text); // thread-safe
|
||||||
|
void chat_render(ChatHandle*, bool* p_open); // ImGui::Begin/End
|
||||||
|
void chat_clear_history(ChatHandle*);
|
||||||
|
void chat_destroy(ChatHandle*);
|
||||||
|
|
||||||
|
// Para apps que quieren leer el historial sin tocar la UI:
|
||||||
|
struct ChatMessage {
|
||||||
|
enum Role { User, Assistant, System, ToolUse, ToolResult } role;
|
||||||
|
std::string text;
|
||||||
|
std::string tool_name; // solo si role==ToolUse|ToolResult
|
||||||
|
int64_t timestamp_ms;
|
||||||
|
};
|
||||||
|
std::vector<ChatMessage> chat_history_snapshot(ChatHandle*);
|
||||||
|
|
||||||
|
} // namespace fn_core
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migracion
|
||||||
|
|
||||||
|
Orden:
|
||||||
|
|
||||||
|
1. **Crear** `cpp/functions/core/claude_chat_panel.{h,cpp,md}` con la API arriba.
|
||||||
|
2. **Tests unitarios** en `cpp/apps/primitives_gallery/demos_chat.cpp`:
|
||||||
|
- chat_create con config minima → no crashea.
|
||||||
|
- mock subprocess (echo de JSON canned) → render muestra mensajes correctos.
|
||||||
|
- chat_send → input limpia, mensaje aparece como User.
|
||||||
|
3. **Migrar `graph_explorer`** primero (codigo mejor estructurado).
|
||||||
|
- `chat.{cpp,h}` reducido a un wrapper de ~30 LoC que construye `ClaudeChatConfig` con `GX_*` env vars.
|
||||||
|
- `app.md` añade `claude_chat_panel_cpp_core` a `uses_functions`.
|
||||||
|
4. **Migrar `navegator_dashboard`** segundo.
|
||||||
|
- Mismo wrapper, env vars `NAVD_*`.
|
||||||
|
5. **Verificacion manual**: en cada app, chat funciona igual que antes.
|
||||||
|
|
||||||
|
## Definicion de hecho
|
||||||
|
|
||||||
|
- `claude_chat_panel.{h,cpp,md}` registrado (`fn index`).
|
||||||
|
- Tests pasan (>= 3 casos en primitives_gallery).
|
||||||
|
- 2 consumidores migrados (chat.cpp en ambas apps reducido a ~30 LoC).
|
||||||
|
- Net LoC eliminadas: ~2400 (se reemplazan ~2500 LoC duplicadas por ~30 LoC config + ~700 LoC en cpp/functions/core).
|
||||||
|
- Tests visuales: golden image del panel renderizado en primitives_gallery.
|
||||||
|
|
||||||
|
## Anti-patrones
|
||||||
|
|
||||||
|
- "Mock everything" — la API NO acepta provider abstracto (Anthropic/OpenAI/...). Es claude-cli especifico. Si emerge un 4to consumidor con OpenAI, abrir issue separado.
|
||||||
|
- Async `co_await` / promises — callbacks bastan, KISS.
|
||||||
|
- Pre-extraer un `claude_subprocess_runner` separado del panel — lo hace 0071f (subprocess_streamer) generico.
|
||||||
|
- Hardcodear el render style en la funcion — exponer flags `cfg.render_compact / cfg.render_avatars` SOLO si un consumidor lo pide.
|
||||||
|
- Acoplar a un schema concreto (`entities`, `cards`, `tabs`) — la funcion solo conoce mensajes; las apps interpretan tool_use_calls a su manera.
|
||||||
|
|
||||||
|
## Riesgos
|
||||||
|
|
||||||
|
- **Divergencia oculta** entre las dos chat.cpp. Mitigacion: hacer un diff exhaustivo antes de extraer y documentar las diferencias en el .md.
|
||||||
|
- **Stream-json parser** es fragil ante cambios de formato de claude-cli. Mitigacion: tests con golden JSON capturado, version-pin del binario en docs.
|
||||||
|
- **History persistence** podria pisar conversaciones si dos apps usan el mismo path. Mitigacion: el path es config — cada app pasa su propio archivo.
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
---
|
||||||
|
id: 0071b
|
||||||
|
title: Extraer `jobs_queue_panel` a cpp/functions/core/ (sub-issue de 0071)
|
||||||
|
status: pending
|
||||||
|
priority: media
|
||||||
|
created: 2026-05-10
|
||||||
|
parent: 0071
|
||||||
|
related_apps: [graph_explorer, odr_console, navegator_dashboard]
|
||||||
|
related_issues: [0065]
|
||||||
|
depends_on: [0071f]
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contexto
|
||||||
|
|
||||||
|
Sub-issue derivado de 0071. Patron jobs queue (cola de trabajos asincronos con progreso, stdout/stderr capture, cancel) duplicado entre apps:
|
||||||
|
|
||||||
|
| Consumidor | Archivos | LoC | Notas |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `projects/osint_graph/apps/graph_explorer/jobs.cpp` + `views_jobs.cpp` | 2 | 1366 + ~300 | Implementacion completa con persistencia DuckDB, agentes, retries |
|
||||||
|
| `projects/osint_graph/apps/odr_console/` (panel Jobs) | 1 | TBD | Por auditar — issue 0066 lo introduce |
|
||||||
|
|
||||||
|
Consumidor potencial inmediato: `navegator_dashboard` para scraping jobs (un crawl = un job).
|
||||||
|
|
||||||
|
Issue **0065** ya existe y propone exactamente esto: "Extraer jobs system de graph_explorer al registry". Este 0071b lo ABSORBE — es la misma extraccion, ahora encadrada bajo el paraguas 0071.
|
||||||
|
|
||||||
|
## Pre-requisito: auditoria de duplicacion
|
||||||
|
|
||||||
|
**ANTES** de extraer, ejecutar:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
diff -u <(grep -c "^" projects/osint_graph/apps/graph_explorer/jobs.cpp) \
|
||||||
|
<(grep -c "^" projects/osint_graph/apps/odr_console/<jobs_file>.cpp)
|
||||||
|
```
|
||||||
|
|
||||||
|
Y comparar manualmente:
|
||||||
|
- Schema de la tabla `jobs` en cada SQLite.
|
||||||
|
- Estados (queued|running|done|failed|canceled).
|
||||||
|
- API publica (submit, cancel, list, on_complete callback).
|
||||||
|
|
||||||
|
Si la divergencia es < 30%, extraer. Si es > 50%, abrir issue de unificacion previa antes de extraer.
|
||||||
|
|
||||||
|
## Objetivo
|
||||||
|
|
||||||
|
Funcion `jobs_queue_panel` en `cpp/functions/core/` con:
|
||||||
|
- Submit jobs con `argv` + `cwd` + `env` + `tags`.
|
||||||
|
- Persistencia automatica en SQLite local (cada app pasa su path).
|
||||||
|
- UI ImGui: lista filtrable por estado, barra progreso, click → ver stdout/stderr.
|
||||||
|
- Cancel/retry.
|
||||||
|
- Worker pool configurable (N workers concurrentes).
|
||||||
|
- Callback global `on_complete(job_id, exit_code)` para que la app reaccione.
|
||||||
|
|
||||||
|
## Dependencia previa
|
||||||
|
|
||||||
|
**0071f** (`subprocess_streamer`) DEBE estar mergeado. El worker pool del jobs_panel usa subprocess_streamer para spawn + capture.
|
||||||
|
|
||||||
|
## API propuesta
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace fn_core {
|
||||||
|
|
||||||
|
struct Job {
|
||||||
|
std::string id; // generado o pasado por la app
|
||||||
|
std::string title; // mostrado en la UI
|
||||||
|
std::vector<std::string> argv; // comando a ejecutar
|
||||||
|
std::string cwd;
|
||||||
|
std::map<std::string, std::string> env;
|
||||||
|
std::vector<std::string> tags; // filtros UI
|
||||||
|
int priority = 0; // mayor = antes
|
||||||
|
};
|
||||||
|
|
||||||
|
struct JobStatus {
|
||||||
|
enum State { Queued, Running, Done, Failed, Canceled } state;
|
||||||
|
int exit_code = -1;
|
||||||
|
std::string stdout_buf; // capturado completo
|
||||||
|
std::string stderr_buf;
|
||||||
|
int64_t queued_at_ms = 0;
|
||||||
|
int64_t started_at_ms = 0;
|
||||||
|
int64_t finished_at_ms = 0;
|
||||||
|
float progress = 0.0f; // 0..1, opcional (parseado de stdout patrones)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct JobsQueueConfig {
|
||||||
|
std::string db_path; // SQLite con tabla jobs (auto-migrada)
|
||||||
|
int max_workers = 2;
|
||||||
|
std::function<void(const std::string& job_id, int exit_code)> on_complete;
|
||||||
|
// Parser opcional para extraer progreso de stdout (ej. regex "(\\d+)%").
|
||||||
|
std::function<float(const std::string& line)> progress_parser;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct JobsHandle;
|
||||||
|
JobsHandle* jobs_create(const JobsQueueConfig& cfg);
|
||||||
|
std::string jobs_submit(JobsHandle*, const Job& j); // returns job_id
|
||||||
|
void jobs_cancel(JobsHandle*, const std::string& job_id);
|
||||||
|
void jobs_retry(JobsHandle*, const std::string& job_id);
|
||||||
|
JobStatus jobs_status(JobsHandle*, const std::string& job_id);
|
||||||
|
std::vector<std::pair<Job, JobStatus>> jobs_list(JobsHandle*, JobStatus::State filter);
|
||||||
|
void jobs_render(JobsHandle*, bool* p_open);
|
||||||
|
void jobs_destroy(JobsHandle*);
|
||||||
|
|
||||||
|
} // namespace fn_core
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migracion
|
||||||
|
|
||||||
|
1. **Auditoria** (ver pre-requisito) — documentar diff entre graph_explorer y odr_console.
|
||||||
|
2. **Schema canonico** — tabla `jobs` en `cpp/functions/core/jobs_queue_panel/migrations/001_init.sql`.
|
||||||
|
3. **Crear** `jobs_queue_panel.{h,cpp,md}` + tests.
|
||||||
|
4. **Tests** en primitives_gallery:
|
||||||
|
- submit `echo hello` → estado Done, exit 0, stdout "hello".
|
||||||
|
- submit `false` → estado Failed, exit 1.
|
||||||
|
- submit + cancel mientras Queued → estado Canceled.
|
||||||
|
- 2 workers, submit 4 jobs → max 2 Running simultaneos.
|
||||||
|
5. **Migrar `graph_explorer`** — `jobs.cpp` reducido a wrapper de ~50 LoC. Migracion de DB existente: copiar filas a la nueva schema si difiere.
|
||||||
|
6. **Migrar `odr_console`** despues.
|
||||||
|
7. **Cerrar issue 0065** apuntando a este 0071b como reemplazo.
|
||||||
|
|
||||||
|
## Definicion de hecho
|
||||||
|
|
||||||
|
- `jobs_queue_panel` registrado, tests pasan.
|
||||||
|
- graph_explorer/jobs.cpp reducido a ~50 LoC (wrapper + config).
|
||||||
|
- odr_console migrado.
|
||||||
|
- Issue 0065 cerrado (movido a `completed/` con nota "absorbido por 0071b").
|
||||||
|
- DB de jobs existente migrada sin perdida de historico.
|
||||||
|
|
||||||
|
## Riesgos
|
||||||
|
|
||||||
|
- **Migracion de schema** de `jobs.duckdb` (si lo es) o `operations.db` puede ser destructiva. Mitigacion: backup de `apps/<app>/operations.db` antes de migrar; script de migracion idempotente con `IF NOT EXISTS`.
|
||||||
|
- **Hilos** — el worker pool corre en background. Cuidado con teardown: `jobs_destroy` debe joinear todos los threads o detach + cancel. Tests con valgrind/asan recomendados.
|
||||||
|
- **odr_console aun no MVP-listo** (issue 0066 pending). Si su jobs no es estable, esperar.
|
||||||
|
|
||||||
|
## Anti-patrones
|
||||||
|
|
||||||
|
- Generalizacion de "task scheduler" (cron, retries exponenciales, prioridades complejas). KISS — FIFO + priority int + cancel basta.
|
||||||
|
- Acoplar al esquema graph (`entities`, `relations`). El panel solo conoce comandos shell.
|
||||||
|
- Workers via `std::async` — usar `std::thread` + `std::condition_variable` simple.
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
---
|
||||||
|
id: 0071g
|
||||||
|
title: Extraer `app_db_init` a cpp/functions/core/ (sub-issue de 0071, Tier 4)
|
||||||
|
status: pending
|
||||||
|
priority: media
|
||||||
|
created: 2026-05-10
|
||||||
|
parent: 0071
|
||||||
|
related_apps: [graph_explorer, navegator_dashboard, kanban, deploy_server, registry_dashboard]
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contexto
|
||||||
|
|
||||||
|
Sub-issue derivado de 0071. **Primitiva Tier 4** — sirve a TODOS los paneles de cualquier app que use SQLite. Bajo riesgo, alta reusabilidad.
|
||||||
|
|
||||||
|
Cada app C++ del registry repite el mismo patron al abrir su SQLite local:
|
||||||
|
|
||||||
|
1. Resolver path: `<exe_dir>/local_files/<app>.db` via `fn::local_path()`.
|
||||||
|
2. Abrir con `sqlite3_open_v2(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)`.
|
||||||
|
3. `PRAGMA journal_mode=WAL`.
|
||||||
|
4. `PRAGMA foreign_keys=ON`.
|
||||||
|
5. `PRAGMA busy_timeout=5000`.
|
||||||
|
6. Aplicar migrations desde `embed.FS` o array de strings (`migrations/001_*.sql`, `002_*.sql`, ...).
|
||||||
|
7. Catch "duplicate column" / "already exists" para idempotencia.
|
||||||
|
8. Verificar version con tabla `_migrations` o assumir orden archivos.
|
||||||
|
|
||||||
|
Sitios actuales con esta logica embebida (~300 LoC duplicadas):
|
||||||
|
|
||||||
|
- `projects/osint_graph/apps/graph_explorer/project_manager.cpp:37-100` (graph_explorer.db)
|
||||||
|
- `projects/osint_graph/apps/graph_explorer/jobs.cpp` (jobs persistence)
|
||||||
|
- `projects/osint_graph/apps/graph_explorer/layout_store.cpp` (layout positions)
|
||||||
|
- `projects/osint_graph/apps/graph_explorer/node_groups.cpp` (groups)
|
||||||
|
- `apps/kanban/db.go::ensureColumns` (Go, fuera de scope C++ pero patron equivalente)
|
||||||
|
- Proxima `navegator_dashboard/local_api.cpp` (history, tabs)
|
||||||
|
|
||||||
|
5+ duplicaciones C++ confirmadas. Rule of three superada con creces.
|
||||||
|
|
||||||
|
## Objetivo
|
||||||
|
|
||||||
|
Funcion `app_db_init` en `cpp/functions/core/` que recibe un path + lista de migraciones SQL y devuelve un `sqlite3*` listo, con todos los pragmas + migraciones aplicadas.
|
||||||
|
|
||||||
|
## API propuesta
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace fn_core {
|
||||||
|
|
||||||
|
struct AppDbConfig {
|
||||||
|
std::string path; // path absoluto al .db
|
||||||
|
std::vector<std::pair<std::string, std::string>> migrations;
|
||||||
|
// ^ pares (nombre_archivo, sql). Aplicados en orden de aparicion.
|
||||||
|
// Ej: {"001_init.sql", "CREATE TABLE ..."}, {"002_add_x.sql", "ALTER ..."}
|
||||||
|
bool wal = true;
|
||||||
|
bool foreign_keys = true;
|
||||||
|
int busy_timeout_ms = 5000;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AppDbResult {
|
||||||
|
sqlite3* conn; // null si error
|
||||||
|
std::string error; // descripcion del error si conn==null
|
||||||
|
int migrations_applied; // cuantas se ejecutaron sin error de duplicado
|
||||||
|
int migrations_skipped; // cuantas eran idempotentes ya aplicadas
|
||||||
|
};
|
||||||
|
|
||||||
|
AppDbResult app_db_init(const AppDbConfig& cfg);
|
||||||
|
|
||||||
|
// Helper para apps que tienen migrations en disco (no embebidas):
|
||||||
|
std::vector<std::pair<std::string, std::string>>
|
||||||
|
app_db_load_migrations_from_dir(const std::string& dir_path);
|
||||||
|
|
||||||
|
} // namespace fn_core
|
||||||
|
```
|
||||||
|
|
||||||
|
## Behavior
|
||||||
|
|
||||||
|
- Crea el directorio del path si no existe.
|
||||||
|
- Aplica cada migracion en transaccion individual.
|
||||||
|
- Captura errores de tipo "duplicate column" / "table already exists" → no fail, suma a `skipped`.
|
||||||
|
- Cualquier otro error de SQL → cierra conn, devuelve null + mensaje.
|
||||||
|
- Logging via `fn_log::log_debug` con nombre del archivo aplicado.
|
||||||
|
|
||||||
|
## Migracion
|
||||||
|
|
||||||
|
1. **Crear** `cpp/functions/core/app_db_init.{h,cpp,md}` + tests.
|
||||||
|
2. **Tests** en primitives_gallery:
|
||||||
|
- DB nueva con 1 migracion → tabla creada, 1 applied.
|
||||||
|
- DB existente con la misma migracion → 0 applied, 1 skipped.
|
||||||
|
- DB con 2 migraciones, segunda falla por SQL invalido → conn null, error claro.
|
||||||
|
- DB con migracion que añade columna existente → catch "duplicate column", continua.
|
||||||
|
3. **Migrar consumidores uno a uno**:
|
||||||
|
- graph_explorer: project_manager.cpp primero (mas codigo).
|
||||||
|
- graph_explorer: jobs, layout_store, node_groups.
|
||||||
|
- navegator_dashboard cuando empiece a tocar SQLite serio.
|
||||||
|
4. Cada migracion en commit propio.
|
||||||
|
|
||||||
|
## Definicion de hecho
|
||||||
|
|
||||||
|
- `app_db_init.{h,cpp,md}` registrado.
|
||||||
|
- Tests pasan (>= 4 casos).
|
||||||
|
- 4 consumidores migrados en graph_explorer.
|
||||||
|
- LoC eliminadas: ~300 (los 4 sitios reducidos a llamadas de ~5 LoC).
|
||||||
|
- `app.md` de cada app actualizado.
|
||||||
|
|
||||||
|
## Riesgos
|
||||||
|
|
||||||
|
- **Bajo**. La operacion es read+exec SQL. No hay concurrencia compleja. Falla detectable inmediato.
|
||||||
|
- Riesgo unico: si la app espera un schema custom no via migrations (ej. `CREATE TABLE IF NOT EXISTS` inline), hay que mover ese SQL a un string `migrations/001_init.sql` antes.
|
||||||
|
|
||||||
|
## Anti-patrones
|
||||||
|
|
||||||
|
- Auto-detectar formato (YAML/JSON) de migrations — recibir `vector<pair<name, sql>>` directo. KISS.
|
||||||
|
- Versioning con tabla `_migrations` — para apps pequeñas basta el archivo numerado + idempotencia. Si una app crece, ella misma migra al patron tabla.
|
||||||
|
- Embedded `embed.FS` baked-in — la funcion recibe pares ya cargados; cada app decide si los embebe con `#embed` (C++23) o los carga del filesystem.
|
||||||
|
- Wrapper RAII sobre `sqlite3*` — fuera de scope. Devuelve raw pointer, la app lo maneja con su propia clase.
|
||||||
@@ -87,4 +87,7 @@
|
|||||||
| [0069](0069-autonomous-agent-loop-self-iterating-tasks.md) | Bucle autonomo de agente — tareas auto-iterativas | pendiente | media | feature | — |
|
| [0069](0069-autonomous-agent-loop-self-iterating-tasks.md) | Bucle autonomo de agente — tareas auto-iterativas | pendiente | media | feature | — |
|
||||||
| [0070](0070-browser-helpers-global-roadmap.md) | Roadmap helpers globales para browser/CDP | pendiente | media | planning | — |
|
| [0070](0070-browser-helpers-global-roadmap.md) | Roadmap helpers globales para browser/CDP | pendiente | media | planning | — |
|
||||||
| [0071](0071-extract-reusable-cpp-panels-roadmap.md) | Roadmap de extraccion de paneles ImGui reutilizables a cpp/functions/ | pendiente | media | planning | — |
|
| [0071](0071-extract-reusable-cpp-panels-roadmap.md) | Roadmap de extraccion de paneles ImGui reutilizables a cpp/functions/ | pendiente | media | planning | — |
|
||||||
|
| [0071a](0071a-extract-claude-chat-panel.md) | Extraer `claude_chat_panel` a cpp/functions/core/ (sub-issue de 0071) | pendiente | alta | refactor | parte de 0071, depende 0071f |
|
||||||
|
| [0071b](0071b-extract-jobs-queue-panel.md) | Extraer `jobs_queue_panel` a cpp/functions/core/ (sub-issue de 0071, absorbe 0065) | pendiente | media | refactor | parte de 0071, depende 0071f |
|
||||||
| [0071f](0071f-extract-subprocess-streamer.md) | Extraer `subprocess_streamer` a cpp/functions/core/ (sub-issue de 0071) | pendiente | media | refactor | parte de 0071 |
|
| [0071f](0071f-extract-subprocess-streamer.md) | Extraer `subprocess_streamer` a cpp/functions/core/ (sub-issue de 0071) | pendiente | media | refactor | parte de 0071 |
|
||||||
|
| [0071g](0071g-extract-app-db-init.md) | Extraer `app_db_init` a cpp/functions/core/ (sub-issue de 0071, Tier 4) | pendiente | media | refactor | parte de 0071 |
|
||||||
|
|||||||
Reference in New Issue
Block a user