From b4cd800027b6eeafe2161d8db1d7627056b4c6c8 Mon Sep 17 00:00:00 2001 From: Egutierrez Date: Sat, 28 Mar 2026 19:14:49 +0100 Subject: [PATCH] docs: reorganizar CLAUDE.md y extraer reglas a .claude/rules/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplifica CLAUDE.md eliminando contenido redundante y extrae las reglas operativas a archivos independientes en .claude/rules/ con un INDEX.md. Cada regla es atómica y referenciable. --- .claude/CLAUDE.md | 669 ++++----------------------- .claude/rules/INDEX.md | 15 + .claude/rules/assertions.md | 3 + .claude/rules/db_locations.md | 5 + .claude/rules/go_packages.md | 1 + .claude/rules/ids_naming.md | 3 + .claude/rules/proposals.md | 3 + .claude/rules/purity.md | 5 + .claude/rules/stubs.md | 1 + .claude/rules/tag_launcher.md | 5 + .claude/rules/types_in_signatures.md | 3 + 11 files changed, 141 insertions(+), 572 deletions(-) create mode 100644 .claude/rules/INDEX.md create mode 100644 .claude/rules/assertions.md create mode 100644 .claude/rules/db_locations.md create mode 100644 .claude/rules/go_packages.md create mode 100644 .claude/rules/ids_naming.md create mode 100644 .claude/rules/proposals.md create mode 100644 .claude/rules/purity.md create mode 100644 .claude/rules/stubs.md create mode 100644 .claude/rules/tag_launcher.md create mode 100644 .claude/rules/types_in_signatures.md diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 6c837914..7d0c29f7 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -2,394 +2,57 @@ Registry personal de codigo reutilizable con busqueda FTS. Diseñado para composicion funcional y agentes. -El sistema tiene **dos bases de datos SQLite**: -- **registry.db** — conocimiento estatico: que funciones y tipos existen, como se componen, y que mejoras se proponen. Vive en la raiz del repositorio. Regenerable con `fn index` (excepto proposals). -- **operations.db** — conocimiento dinamico por proyecto: que entities existen, como se relacionan, que ejecuciones se han hecho, y que calidad tienen los datos. Vive en cada proyecto que usa el registry. +**Dos bases de datos SQLite:** +- **registry.db** (raiz) — funciones, tipos, proposals. Regenerable con `fn index` (excepto proposals). +- **operations.db** (por app en `apps/*/`) — entities, relations, executions, assertions. Datos vivos. ---- - -## Arquitectura: dos BDs, un bucle - -``` -┌─────────────────────────────────────────────────────────────────────┐ -│ registry.db (central) │ -│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ -│ │ functions │ │ types │ │proposals │ │ -│ │ (120+) │ │ (31+) │ │(auto/man)│ │ -│ └──────────┘ └──────────┘ └──────────┘ │ -│ ↑ busca funciones ↑ crea proposals │ -└───────┼────────────────────────────┼────────────────────────────────┘ - │ │ -┌───────┼────────────────────────────┼────────────────────────────────┐ -│ ↓ usa en relaciones │ reactive loop │ -│ operations.db (por proyecto) │ -│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ -│ │ entities │→ │relations │ │executions│→ │assertions │ │ -│ │ │ │ │ │ │ │ → assertion_results│ │ -│ └──────────┘ └──────────┘ └──────────┘ └──────────────────┘ │ -│ ┌──────────────┐ ┌──────────────┐ │ -│ │relation_inputs│ │types_snapshot│ │ -│ └──────────────┘ └──────────────┘ │ -└─────────────────────────────────────────────────────────────────────┘ -``` - -**Bucle autonomo:** EJECUTAR → EVALUAR → REACCIONAR → PROPONER -1. Un pipeline se ejecuta → se registra en `executions` -2. Las `assertions` activas de la entity se evaluan automaticamente -3. Si critical falla → entity pasa a `corrupted` + se crea `proposal` en registry -4. Si warning falla → entity pasa a `stale` -5. El humano revisa proposals y decide si implementar mejoras +**Reglas y convenciones:** ver `.claude/rules/INDEX.md` --- ## Explorar el registry (USAR SIEMPRE) -La BD SQLite `registry.db` es tu mapa del repositorio. Antes de escribir codigo, SIEMPRE consultala para saber que existe, evitar duplicados y descubrir funciones reutilizables. +Antes de escribir codigo, SIEMPRE consulta registry.db para evitar duplicados y descubrir funciones reutilizables. ```bash -# Buscar funciones por texto libre (FTS5) +# FTS5 sqlite3 registry.db "SELECT id, kind, purity, description FROM functions WHERE id IN (SELECT id FROM functions_fts WHERE functions_fts MATCH 'slice') ORDER BY name;" -# Listar todas las funciones de un dominio +# Por dominio sqlite3 registry.db "SELECT id, purity, signature FROM functions WHERE domain = 'finance' ORDER BY name;" -# Listar solo puras de un dominio +# Puras de un dominio sqlite3 registry.db "SELECT id, signature FROM functions WHERE domain = 'core' AND purity = 'pure' ORDER BY name;" -# Listar solo impuras -sqlite3 registry.db "SELECT id, domain, error_type FROM functions WHERE purity = 'impure' ORDER BY domain, name;" - -# Buscar tipos por dominio +# Tipos sqlite3 registry.db "SELECT id, algebraic, description FROM types WHERE domain = 'cybersecurity';" -# Ver que funciones usa un pipeline o funcion compuesta +# Dependencias sqlite3 registry.db "SELECT id, uses_functions, uses_types FROM functions WHERE uses_functions != '[]';" -# Ver funciones que dependen de un tipo concreto -sqlite3 registry.db "SELECT id FROM functions WHERE uses_types LIKE '%ohlcv_go_finance%';" - -# Buscar por tag -sqlite3 registry.db "SELECT id, tags FROM functions WHERE tags LIKE '%generic%';" - -# Contar entradas por dominio -sqlite3 registry.db "SELECT domain, COUNT(*) FROM functions GROUP BY domain;" - -# Ver todo el schema -sqlite3 registry.db ".schema" - -# Ver proposals pendientes +# Proposals pendientes sqlite3 registry.db "SELECT id, kind, status, title FROM proposals WHERE status = 'pending';" -``` -La BD usa WAL mode — puedes leerla mientras se escribe sin bloqueos. +# Schema completo +sqlite3 registry.db ".schema" +``` --- -## Tablas: registry.db - -### functions (27 columnas) - -Cada funcion registrada: su firma, purity, dependencias, y metadata. - -| Columna | Tipo | Descripcion | -|---|---|---| -| id | TEXT PK | `{name}_{lang}_{domain}` | -| name | TEXT | snake_case | -| kind | TEXT | `function` / `pipeline` / `component` | -| lang | TEXT | `go` / `python` / `typescript` / `sql` | -| domain | TEXT | `core` / `finance` / `datascience` / `cybersecurity` / ... | -| version | TEXT | semver | -| purity | TEXT | `pure` / `impure` | -| signature | TEXT | firma completa | -| description | TEXT | que hace y cuando usarla | -| tags | JSON[] | etiquetas | -| uses_functions | JSON[] | IDs de funciones que invoca | -| uses_types | JSON[] | IDs de tipos que recibe | -| returns | JSON[] | IDs de tipos que devuelve (no tipos nativos) | -| returns_optional | INT | 0/1 | -| error_type | TEXT | ID del tipo de error (obligatorio si impure) | -| imports | JSON[] | dependencias externas | -| example | TEXT | codigo de ejemplo extraido del .md | -| tested | INT | 0/1 | -| tests | JSON[] | nombres de tests | -| test_file_path | TEXT | ruta al archivo de test | -| file_path | TEXT | ruta relativa al .go/.py/.tsx | -| props | JSON[] | solo components: PropDef[] | -| emits | JSON[] | solo components: eventos emitidos | -| has_state | INT? | solo components: nullable | -| framework | TEXT | solo components: react/vue/... | -| variant | JSON[] | solo components: variantes | -| created_at, updated_at | TEXT | RFC3339 | - -### types (13 columnas) - -Tipos algebraicos: product (struct) y sum (interface/union). - -| Columna | Tipo | Descripcion | -|---|---|---| -| id | TEXT PK | `{name}_{lang}_{domain}` | -| name | TEXT | snake_case | -| lang | TEXT | lenguaje | -| domain | TEXT | dominio | -| version | TEXT | semver | -| algebraic | TEXT | `product` / `sum` | -| definition | TEXT | codigo fuente del tipo | -| description | TEXT | descripcion | -| tags | JSON[] | etiquetas | -| uses_types | JSON[] | IDs de tipos que compone (sin auto-ref) | -| file_path | TEXT | ruta relativa | -| created_at, updated_at | TEXT | RFC3339 | - -### proposals (11 columnas) - -Mejoras propuestas al registry. Las crea el agente (reactive loop) o el humano. - -| Columna | Tipo | Descripcion | -|---|---|---| -| id | TEXT PK | `proposal_{timestamp}` o manual | -| kind | TEXT | `new_function` / `new_type` / `improve_function` / `improve_type` / `new_pipeline` | -| target_id | TEXT | ID de la funcion/tipo a mejorar (obligatorio para improve_*) | -| title | TEXT | titulo corto | -| description | TEXT | detalle | -| evidence | JSON{} | datos que justifican la propuesta (assertion failures, metrics, etc) | -| status | TEXT | `pending` / `approved` / `rejected` / `implemented` | -| created_by | TEXT | quien creo (agente, humano, reactive_loop) | -| reviewed_by | TEXT | quien reviso | -| created_at, updated_at | TEXT | RFC3339 | - -### FTS5 (busqueda full-text) - -- `functions_fts` — indexa: id, name, description, tags, signature, domain -- `types_fts` — indexa: id, name, description, tags, domain -- `proposals_fts` — indexa: id, title, description, evidence - -Sincronizados automaticamente via triggers (INSERT/UPDATE/DELETE). - ---- - -## Tablas: operations.db - -### entities (12 columnas) - -Instancia concreta de un tipo del registry dentro de un proyecto. - -| Columna | Tipo | Descripcion | -|---|---|---| -| id | TEXT PK | identificador unico en el proyecto | -| name | TEXT | nombre descriptivo | -| type_ref | TEXT | ID del tipo en registry (ej: `ohlcv_go_finance`) | -| status | TEXT | `active` / `stale` / `corrupted` / `archived` | -| description | TEXT | que representa esta entity | -| domain | TEXT | dominio | -| tags | JSON[] | etiquetas | -| source | TEXT | origen de los datos (obligatorio) | -| metadata | JSON{} | campos del tipo instanciados con valores reales | -| notes | TEXT | notas libres | -| created_at, updated_at | TEXT | RFC3339 | - -### relations (17 columnas) - -Conexion/transformacion entre entities. Puede ser causal (via funcion) o semantica. - -| Columna | Tipo | Descripcion | -|---|---|---| -| id | TEXT PK | identificador | -| name | TEXT | nombre descriptivo | -| from_entity | TEXT | entity origen | -| to_entity | TEXT | entity destino (obligatorio) | -| via | TEXT | ID de funcion del registry que transforma (si vacio = semantica) | -| description | TEXT | que hace esta relacion | -| purity | TEXT | `pure` / `impure` / `` | -| direction | TEXT | `unidirectional` / `bidirectional` / `inverse` | -| weight | REAL | 0.0-1.0, importancia | -| status | TEXT | `designed` / `implemented` / `tested` / `running` / `deprecated` | -| started_at, ended_at | TEXT | ciclo de vida | -| order | INT | para secuencias | -| tags | JSON[] | etiquetas | -| notes | TEXT | notas | -| created_at, updated_at | TEXT | RFC3339 | - -### relation_inputs (5 columnas) - -Multi-input para relaciones N→1 (joins, merges, agregaciones). - -| Columna | Tipo | Descripcion | -|---|---|---| -| id | TEXT PK | | -| relation_id | TEXT FK | referencia a relations.id (CASCADE delete) | -| entity_id | TEXT FK | referencia a entities.id | -| role | TEXT | rol semantico del input (ej: "left", "right", "config") | -| order | INT | orden de procesamiento | - -### types_snapshot (7 columnas) - -Copia inmutable de un tipo del registry en el momento de uso. Hace operations.db autonoma. - -| Columna | Tipo | Descripcion | -|---|---|---| -| id | TEXT PK | mismo ID que en registry.types | -| version | TEXT | version capturada | -| lang | TEXT | lenguaje | -| algebraic | TEXT | product/sum | -| definition | TEXT | codigo fuente capturado | -| description | TEXT | descripcion capturada | -| snapped_at | TEXT | cuando se hizo el snapshot | - -### executions (12 columnas) - -Cada ejecucion de un pipeline. Memoria de comportamiento del sistema. - -| Columna | Tipo | Descripcion | -|---|---|---| -| id | TEXT PK | `exec_{timestamp}` o manual | -| pipeline_id | TEXT | ID de funcion del registry (ej: `tick_to_ohlcv_go_finance`) | -| relation_id | TEXT | relacion asociada (opcional) | -| status | TEXT | `success` / `failure` / `partial` | -| started_at | TEXT | inicio (obligatorio) | -| ended_at | TEXT | fin (nullable si en progreso) | -| duration_ms | INT | auto-calculado si started_at y ended_at presentes | -| records_in | INT | registros de entrada (nullable) | -| records_out | INT | registros de salida (nullable) | -| error | TEXT | mensaje de error si fallo | -| metrics | JSON{} | metricas custom (ej: `{"mean_close": 42000}`) | -| created_at | TEXT | RFC3339 | - -### assertions (9 columnas) - -Regla de calidad formal sobre una entity. Evaluable automaticamente contra metadata. - -| Columna | Tipo | Descripcion | -|---|---|---| -| id | TEXT PK | | -| entity_id | TEXT FK | referencia a entities.id | -| name | TEXT | nombre descriptivo | -| kind | TEXT | tipo libre: `range`, `null`, `statistical`, `consistency`, `freshness`, o custom | -| rule | TEXT | expresion SQL evaluable (ver motor de evaluacion abajo) | -| severity | TEXT | `critical` / `warning` / `info` | -| description | TEXT | que verifica | -| active | INT | 0/1 — solo las activas se evaluan | -| created_at | TEXT | RFC3339 | - -### assertion_results (7 columnas) - -Historial de evaluaciones de assertions. - -| Columna | Tipo | Descripcion | -|---|---|---| -| id | TEXT PK | | -| assertion_id | TEXT FK | referencia a assertions.id | -| execution_id | TEXT | referencia a executions.id (vacio si eval manual) | -| status | TEXT | `pass` / `fail` / `skip` | -| value | JSON{} | datos capturados en el momento de evaluacion | -| message | TEXT | detalle del resultado | -| evaluated_at | TEXT | RFC3339 | - -### FTS5 operations - -- `entities_fts` — indexa: id, name, description, tags, domain -- `assertions_fts` — indexa: id, name, description, rule - ---- - -## Motor de evaluacion de assertions - -Las rules se escriben como expresiones SQL. Campos sin prefijo se reescriben automaticamente a `json_extract(metadata, '$.campo')`: - -``` -close > 0 → json_extract(metadata, '$.close') > 0 -low <= close AND close <= high → json_extract(metadata, '$.low') <= ... -open IS NOT NULL → json_extract(metadata, '$.open') IS NOT NULL -``` - -Si la rule ya usa `json_extract`, se deja como esta. Palabras SQL (AND, OR, NOT, IS, NULL, BETWEEN, etc) y funciones SQLite (datetime, abs, max, min, etc) no se reescriben. - -**Kinds documentados** (puedes añadir nuevos sin tocar schema): - -| Kind | Descripcion | Ejemplo de rule | -|---|---|---| -| `range` | Valor dentro de rango | `close BETWEEN 0 AND 1000000` | -| `null` | Campo no nulo | `open IS NOT NULL` | -| `consistency` | Relacion entre campos | `low <= close AND close <= high` | -| `freshness` | Datos recientes | `json_extract(metadata, '$.ts') > datetime('now', '-1 hour')` | -| `statistical` | Desviacion estadistica | (evaluar externamente, registrar manual) | - -**Dos modos:** -- **Auto**: `fn ops assertion eval --entity-id X` ejecuta rules SQL contra `entities.metadata` -- **Manual**: `fn ops assertion result add` registra resultados de assertions que el sistema no puede evaluar - -**Bucle reactivo** (con `--react`): -- `fn ops assertion eval --entity-id X --react` evalua Y reacciona: - - Critical fail → entity.status = `corrupted` + auto-crea proposal en registry.db - - Warning fail → entity.status = `stale` (solo si era `active`) - - Info fail → sin cambio - ---- - -## Sistema de migraciones - -Ambas BDs usan un sistema de migraciones con `embed.FS`: - -``` -registry/migrations/ - 001_init.sql # functions + types + FTS - 002_proposals.sql # proposals + FTS - -fn_operations/migrations/ - 001_init.sql # entities + relations + relation_inputs + types_snapshot + FTS - 002_executions_assertions.sql # executions + assertions + assertion_results + FTS -``` - -- Tabla `schema_migrations` en cada BD rastrea versiones aplicadas -- `CREATE TABLE IF NOT EXISTS` + transacciones por migracion = idempotente -- Al hacer `Open()` se aplican automaticamente las migraciones pendientes -- Para añadir una nueva migracion: crear `NNN_nombre.sql` en la carpeta correspondiente - ---- - -## Estructura del repositorio +## Estructura ``` fn-registry/ - functions/ # Codigo y docs de funciones - core/ # Utilidades genericas (filter, map, pipeline, retry...) - finance/ # Indicadores, riesgo, IO de mercado - datascience/ # Estadistica, DSP, IO de datos - cybersecurity/ # Crypto, analisis de red, IO de seguridad - pipelines/ # Composiciones de funciones, siempre impuras - components/ # Componentes React (.tsx) - types/ # Tipos algebraicos (product y sum) - core/ # Result, Option, Pair, Error - finance/ # OHLCV, Tick, BollingerResult, DrawdownResult - datascience/ # OutlierResult - cybersecurity/ # CIDRBlock, ThreatResult, PortResult + functions/{domain}/ # .go + .md por funcion (core, finance, datascience, cybersecurity) + functions/pipelines/ # Composiciones, siempre impuras + functions/components/ # React (.tsx) + types/{domain}/ # .go + .md por tipo registry/ # Paquete Go: modelos, SQLite, parser, indexer, validacion, migraciones - models.go # Function, Type, Proposal structs + enums (Kind, Purity, Algebraic, ProposalKind, ProposalStatus) - db.go # Open/Close/Drop + WAL + migraciones - store.go # CRUD: Insert/Get/Update/Delete/List/Search para functions, types, proposals - validate.go # ValidateFunction, ValidateType, ValidateProposal - parser.go # ParseFunctionMD, ParseTypeMD (YAML frontmatter) - indexer.go # Index() — two-pass: parse → validate refs → insert - migrate.go # Motor de migraciones (embed.FS) - migrations/ # Archivos .sql numerados - fn_operations/ # Paquete Go: operations database (libreria, NO apps) - models.go # Entity, Relation, RelationInput, TypeSnapshot, Execution, Assertion, AssertionResult + enums - db.go # Open/Close/Drop/Conn - store.go # CRUD para todas las tablas - validate.go # ValidateEntity, ValidateRelation, ValidateExecution, ValidateAssertion, DetectCycle - operations.go # Alto nivel: InsertEntityWithSnapshot, InsertRelationSafe, React, ExecuteAndReact - eval.go # Motor de evaluacion: rewriteRule, EvalAssertion, EvalEntityAssertions - migrate.go # Motor de migraciones - migrations/ # Archivos .sql numerados - apps/ # Aplicaciones ejecutables (TUIs, CLIs) — modulos Go independientes - docker_tui/ # TUI fullscreen para gestionar Docker - pipeline_launcher/ # TUI para lanzar pipelines y registrar ejecuciones - cmd/fn/ # CLI - main.go # Subcomandos: index, search, list, show, add, ops, proposal - ops.go # fn ops: entity, relation, graph, snapshot, execution, assertion - proposal.go # fn proposal: add, list, show, update - docs/ # Specs de diseño (fuente de verdad del schema) + fn_operations/ # Paquete Go: operations database (libreria) + apps/ # Apps ejecutables (TUIs, CLIs) — modulos Go independientes, cada una con su operations.db + cmd/fn/ # CLI principal + docs/ # Specs de diseño docs/templates/ # Plantillas de frontmatter - registry.db # Indice SQLite FTS5+WAL (regenerable con fn index, excepto proposals) ``` --- @@ -397,200 +60,107 @@ fn-registry/ ## Build ```bash -CGO_ENABLED=1 go build -tags fts5 ./... -CGO_ENABLED=1 go test -tags fts5 ./... CGO_ENABLED=1 go build -tags fts5 -o fn ./cmd/fn/ +CGO_ENABLED=1 go test -tags fts5 ./... ``` --- -## CLI completo (cmd/fn) - -### Registry +## CLI ```bash -fn index # Regenera registry.db desde los .md -fn search "texto" # Busqueda FTS en functions + types +# Registry +fn index # Regenera registry.db +fn search "texto" # FTS en functions + types fn search -k function -p pure -d core "slice" -fn list # Lista todo -fn list -d finance -k function # Lista por dominio y kind -fn show filter_slice_go_core # Muestra entrada completa -fn add -k function # Muestra template para copiar -``` +fn list [-d domain] [-k kind] +fn show +fn add -k function # Template -### Proposals - -```bash -fn proposal add --kind new_function --title "..." --created-by agent [--target-id ] [--evidence '{}'] [--description "..."] +# Proposals +fn proposal add --kind new_function --title "..." --created-by agent [--target-id ] fn proposal list [-k kind] [-s status] fn proposal show fn proposal update --status approved [--reviewed-by lucas] -``` -### Operations - -```bash -fn ops init [path] # Crea operations.db en el directorio -fn ops help # Ayuda - -# Entities -fn ops entity add --id --name --type-ref --source [--metadata '{}'] [--domain d] [--tags t1,t2] -fn ops entity list [--domain d] [--status s] -fn ops entity show -fn ops entity delete - -# Relations -fn ops relation add --id --name --from --to [--via ] [--direction uni] [--status designed] -fn ops relation list [--from ] -fn ops relation show -fn ops relation delete - -# Graph -fn ops graph # ASCII graph de entities y relations - -# Snapshots -fn ops snapshot list # Lista type snapshots -fn ops snapshot check # Compara snapshots vs registry actual -fn ops snapshot update |--all # Re-snapshot desde registry - -# Executions -fn ops execution add --pipeline-id --status success [--started-at ] [--ended-at ] [--records-in N] [--records-out N] [--metrics '{}'] [--error "msg"] -fn ops execution list [--pipeline-id ] [--relation-id ] [-s status] -fn ops execution show - -# Assertions -fn ops assertion add --entity-id --name "close positivo" --kind range --rule "close > 0" --severity critical [--description "..."] -fn ops assertion list [--entity-id ] [--active] [--inactive] -fn ops assertion show # Incluye ultimos 5 resultados -fn ops assertion delete -fn ops assertion eval --entity-id [--execution-id ] [--react] # Evalua assertions activas - -# Assertion results (registro manual) -fn ops assertion result add --assertion-id --status pass|fail|skip [--execution-id ] [--value '{}'] [--message "..."] -fn ops assertion result list [--assertion-id ] [--execution-id ] +# Operations (desde directorio con operations.db) +fn ops init [path] +fn ops entity add|list|show|delete +fn ops relation add|list|show|delete +fn ops graph +fn ops snapshot list|check|update +fn ops execution add|list|show +fn ops assertion add|list|show|delete|eval [--react] +fn ops assertion result add|list ``` `FN_REGISTRY_ROOT` env var permite que `fn ops` acceda a registry.db desde cualquier directorio. --- -## Reglas para añadir funciones nuevas +## Añadir funciones -### Antes de crear +1. Consulta la BD para verificar que no existe algo similar +2. Crea dos archivos: `functions/{domain}/{name}.go` + `functions/{domain}/{name}.md` +3. Ejecuta `./fn index` y verifica con `./fn show {id}` -1. **Consulta la BD** para verificar que no existe algo similar: - ```bash - sqlite3 registry.db "SELECT id, description FROM functions WHERE id IN (SELECT id FROM functions_fts WHERE functions_fts MATCH 'tu busqueda');" - ``` -2. **Identifica el dominio** correcto: core, finance, datascience, cybersecurity, o crea uno nuevo si no encaja -3. **Decide la purity**: pure si no tiene side effects, impure si tiene IO/estado/goroutines/tiempo +Frontmatter del .md — ver template completo en `docs/templates/` o con `fn add -k function`. -### Archivos a crear +Reglas de integridad (el indexer las valida): +- Pipeline → siempre impuro + uses_functions no vacio +- Pure → returns_optional: false + error_type: "" +- Impure → error_type obligatorio (usar `error_go_core`) +- tested: true → test_file_path y tests obligatorios +- uses_functions, uses_types, returns, error_type → IDs existentes +- Component → framework obligatorio, returns vacio (usar emits) +- file_path siempre relativa, IDs formato `{name}_{lang}_{domain}` +- Campo `returns` solo para IDs del registry, NO tipos nativos de Go -Cada funcion requiere EXACTAMENTE dos archivos: +## Añadir tipos -1. **Implementacion** `functions/{domain}/{name}.go` — codigo real, compilable -2. **Documentacion** `functions/{domain}/{name}.md` — frontmatter YAML con metadata - -### Formato del .md (frontmatter YAML) - -```yaml ---- -name: nombre_snake_case -kind: function # function | pipeline | component -lang: go # go | python | typescript | sql -domain: core # core | finance | datascience | cybersecurity | ... -version: "1.0.0" -purity: pure # pure | impure -signature: "func NombreCompleto(...) ..." -description: "Descripcion en español de que hace y cuando usarla." -tags: [tag1, tag2, tag3] -uses_functions: [] # IDs de funciones del registry que invoca -uses_types: [] # IDs de tipos del registry que recibe -returns: [] # IDs de tipos del registry que devuelve -returns_optional: false -error_type: "" # ID de tipo de error, obligatorio si impure -imports: [] # dependencias externas fuera del registry -tested: false -tests: [] -test_file_path: "" -file_path: "functions/{domain}/{name}.go" ---- - -## Ejemplo - -` `` go -resultado := MiFuncion(input) -` `` - -## Notas - -Explicacion adicional si es necesario. -``` - -### Reglas de integridad (el indexer las valida) - -| Regla | Condicion | -|---|---| -| Pipeline siempre impuro | `kind: pipeline` → `purity: impure` + `uses_functions` no vacio | -| Pura sin side effects | `purity: pure` → `returns_optional: false` + `error_type: ""` | -| Impura declara errores | `purity: impure` → `error_type` obligatorio (usar `error_go_core`) | -| Tests coherentes | `tested: true` → `test_file_path` y `tests` obligatorios | -| Referencias validas | `uses_functions`, `uses_types`, `returns`, `error_type` deben apuntar a IDs existentes | -| Component tiene framework | `kind: component` → `framework` obligatorio, `returns` vacio (usar `emits`) | -| Rutas relativas | `file_path` siempre relativa a la raiz, nunca absoluta | -| IDs unicos | Formato `{name}_{lang}_{domain}`, colisiones rechazadas | - -### Campo `returns` vs tipo nativo - -El campo `returns` en el .md es para IDs de tipos del registry (ej: `ohlcv_go_finance`), NO para tipos nativos de Go (`float64`, `string`, `bool`). Si la funcion devuelve tipos nativos, deja `returns: []`. - -### Despues de crear - -```bash -# Regenerar el indice -./fn index -# o -CGO_ENABLED=1 go build -tags fts5 -o fn ./cmd/fn/ && ./fn index - -# Verificar que se indexo sin errores -./fn show {name}_{lang}_{domain} -``` +Dos archivos: `types/{domain}/{name}.go` + `types/{domain}/{name}.md`. Ver template en `docs/templates/`. --- -## Reglas para añadir tipos nuevos +## Bucle reactivo: CONSTRUIR → EJECUTAR → RECOPILAR → ANALIZAR → MEJORAR -Cada tipo requiere dos archivos: `types/{domain}/{name}.go` y `types/{domain}/{name}.md`. +### 1. CONSTRUIR +- Agente consulta registry → recupera funciones testeadas por FTS sobre `name`, `description`, `tags`. +- Razona sobre composabilidad comparando `returns` con `uses_types`. +- Prioriza funciones puras para el nucleo, aisla impuras en los bordes. +- Registra el pipeline en operations como `status: designed → implemented`. +- **BD:** `registry.db` (functions, types) → `operations.db` (relations, entities) -```yaml ---- -name: nombre_snake_case -lang: go -domain: core -version: "1.0.0" -algebraic: product # product (struct) | sum (interface/union) -definition: | - type MiTipo struct { ... } -description: "Descripcion en español." -tags: [tag1, tag2] -uses_types: [] # IDs de otros tipos que compone (sin auto-referencias) -file_path: "types/{domain}/{name}.go" ---- -``` +### 2. EJECUTAR +- Pipeline corre → inserta registro en `executions` con `duration_ms`, `records_in`, `records_out`, `metrics`. +- `operations.relations.status = running`. +- Si falla → `execution.status = failure`, `error` capturado. +- **BD:** `operations.db` (executions, relations) ---- +### 3. RECOPILAR +- Entities se pueblan — `metadata` contiene los valores concretos de los campos del tipo. +- `types_snapshot` garantiza que `operations.db` es autonomo sin `registry.db`. +- El agente actualiza `entity.status` segun los datos recibidos. +- **BD:** `operations.db` (entities, types_snapshot) -## Convenciones +### 4. ANALIZAR +- Agente evalua todas las `assertions` activas sobre las entities producidas. +- Compara `metrics` de la ejecucion actual con `executions` historicas. +- `critical` falla → `entity.status = corrupted`. +- `warning` falla → `entity.status = stale`. +- Resultados en `assertion_results` con `value` concreto para debugging. +- **BD:** `operations.db` (assertions, assertion_results, entities.status) -- **IDs:** `{name}_{lang}_{domain}` (ej: `filter_slice_go_core`) -- **Nombres:** snake_case para funciones, PascalCase para tipos en Go -- **Paquete Go:** el nombre del directorio (core, finance, datascience, cybersecurity) -- **Tipos en firmas:** usar tipos nativos (float64, []float64, string) para evitar imports circulares entre paquetes de funciones. Documentar los tipos del registry en `uses_types`/`returns` del .md -- **Purity:** puras en el centro, impuras en los bordes. Una pura NUNCA depende de una impura -- **Stubs impuros:** si la implementacion real requiere dependencias externas no disponibles, crear stub con `return ..., fmt.Errorf("not implemented")` y documentar completamente el .md -- **Assertions:** kind es texto libre — puedes inventar nuevos kinds sin tocar schema -- **Proposals:** las crea el bucle reactivo automaticamente (created_by: reactive_loop) o el humano/agente manualmente +### 5. MEJORAR +- Si assertions fallan o metricas degradan → agente escribe en `proposals`. +- `proposals.evidence` referencia los `assertion_ids` y `execution_ids` que lo justifican. +- El humano revisa `proposals.status: pending → approved → implemented`. +- El registry crece de forma controlada y trazable. +- **BD:** `registry.db` (proposals) + +Codigo: `ExecuteAndReact()` en `fn_operations/operations.go` ejecuta pasos 2-4. +CLI: `fn ops assertion eval --entity-id X --react` ejecuta pasos 4-5. +Las assertion rules son expresiones SQL. Campos sin prefijo se reescriben a `json_extract(metadata, '$.campo')`. --- @@ -598,53 +168,8 @@ file_path: "types/{domain}/{name}.go" | Que | Donde | |---|---| -| Codigo | archivos .go / .py / .tsx | -| Documentacion | archivos .md junto al codigo | -| Diseño del schema | carpeta docs/ | -| Indice de busqueda | registry.db (regenerable con `fn index`) | -| Proposals | registry.db tabla proposals (NO regenerable, son datos vivos) | -| Entities, relations | operations.db por proyecto (datos vivos) | -| Executions, assertions | operations.db por proyecto (datos vivos) | - -**Importante:** `fn index` regenera functions y types desde los .md pero NO toca proposals. Las proposals, entities, relations, executions, assertions y assertion_results son datos vivos que persisten. - ---- - -## Codigo Go: patrones clave - -### JSON en columnas TEXT - -Arrays y objetos se guardan como JSON serializado en columnas TEXT: - -```go -marshalStrings([]string) string // ["a","b"] → string -unmarshalStrings(string) []string // string → ["a","b"] -marshalJSON(map[string]any) string // {k:v} → string -unmarshalJSON(string) map[string]any -``` - -### Validacion - -Acumula errores, retorna nil o *ValidationError: - -```go -func ValidateX(x *X) *ValidationError { - var errs []string - if x.Name == "" { errs = append(errs, "name required") } - if len(errs) > 0 { return &ValidationError{ID: x.ID, Errors: errs} } - return nil -} -``` - -### Migraciones - -```go -//go:embed migrations/*.sql -var migrationsFS embed.FS - -func migrate(conn *sql.DB) error { ... } // aplica pendientes en transacciones -``` - -### Cycle detection - -Solo relaciones causales (via != "") se verifican. BFS desde to_entity buscando from_entity. +| Codigo | .go / .py / .tsx | +| Metadata | .md junto al codigo | +| Schema de BDs | `sqlite3 *.db ".schema"` o `docs/` | +| Indice | registry.db (`fn index`) | +| Proposals, entities, executions, assertions | datos vivos en sus BDs | diff --git a/.claude/rules/INDEX.md b/.claude/rules/INDEX.md new file mode 100644 index 00000000..804af9e3 --- /dev/null +++ b/.claude/rules/INDEX.md @@ -0,0 +1,15 @@ +# Rules Index + +Reglas operativas del proyecto. Cada archivo es una regla independiente. + +| # | Archivo | Regla | +|---|---------|-------| +| 01 | [db_locations.md](db_locations.md) | Ubicacion de registry.db y operations.db | +| 02 | [ids_naming.md](ids_naming.md) | Formato de IDs y convenciones de nombres | +| 03 | [purity.md](purity.md) | Reglas de pureza funcional | +| 04 | [types_in_signatures.md](types_in_signatures.md) | Tipos nativos en firmas, registry types en .md | +| 05 | [stubs.md](stubs.md) | Stubs impuros para dependencias externas | +| 06 | [assertions.md](assertions.md) | Kinds de assertions son texto libre | +| 07 | [proposals.md](proposals.md) | Quien crea proposals y cuando | +| 08 | [tag_launcher.md](tag_launcher.md) | Tag launcher para Pipeline Launcher TUI | +| 09 | [go_packages.md](go_packages.md) | Nombre de paquete Go = nombre del directorio | diff --git a/.claude/rules/assertions.md b/.claude/rules/assertions.md new file mode 100644 index 00000000..e65e236c --- /dev/null +++ b/.claude/rules/assertions.md @@ -0,0 +1,3 @@ +El campo `kind` de assertions es texto libre. Se pueden inventar nuevos kinds sin tocar schema. + +Kinds documentados: `range`, `null`, `statistical`, `consistency`, `freshness`. diff --git a/.claude/rules/db_locations.md b/.claude/rules/db_locations.md new file mode 100644 index 00000000..8227e34a --- /dev/null +++ b/.claude/rules/db_locations.md @@ -0,0 +1,5 @@ +`registry.db` SOLO existe en la raiz del repositorio, NUNCA en subdirectorios ni apps. + +`operations.db` SOLO existe dentro de cada app (`apps/*/operations.db`), NUNCA en la raiz. Cada app tiene su propia operations.db con sus entities, relations y executions independientes. + +Si se detecta un registry.db fuera de la raiz o un operations.db en la raiz, es un error y debe eliminarse. diff --git a/.claude/rules/go_packages.md b/.claude/rules/go_packages.md new file mode 100644 index 00000000..6b6a7152 --- /dev/null +++ b/.claude/rules/go_packages.md @@ -0,0 +1 @@ +El nombre del paquete Go es el nombre del directorio: core, finance, datascience, cybersecurity. diff --git a/.claude/rules/ids_naming.md b/.claude/rules/ids_naming.md new file mode 100644 index 00000000..d417cf23 --- /dev/null +++ b/.claude/rules/ids_naming.md @@ -0,0 +1,3 @@ +IDs siguen el formato `{name}_{lang}_{domain}` (ej: `filter_slice_go_core`). + +Nombres de funciones en snake_case. Tipos en PascalCase para Go. diff --git a/.claude/rules/proposals.md b/.claude/rules/proposals.md new file mode 100644 index 00000000..5baa2cc3 --- /dev/null +++ b/.claude/rules/proposals.md @@ -0,0 +1,3 @@ +Las proposals las crea el bucle reactivo automaticamente (`created_by: reactive_loop`) o el humano/agente manualmente. + +Son datos vivos en registry.db — `fn index` NO las toca ni regenera. diff --git a/.claude/rules/purity.md b/.claude/rules/purity.md new file mode 100644 index 00000000..7f1696ed --- /dev/null +++ b/.claude/rules/purity.md @@ -0,0 +1,5 @@ +Puras en el centro, impuras en los bordes. Una funcion pura NUNCA depende de una impura. + +- `purity: pure` → `returns_optional: false` + `error_type: ""` +- `purity: impure` → `error_type` obligatorio (usar `error_go_core`) +- `kind: pipeline` → siempre `purity: impure` + `uses_functions` no vacio diff --git a/.claude/rules/stubs.md b/.claude/rules/stubs.md new file mode 100644 index 00000000..64522f55 --- /dev/null +++ b/.claude/rules/stubs.md @@ -0,0 +1 @@ +Si la implementacion real requiere dependencias externas no disponibles, crear stub con `return ..., fmt.Errorf("not implemented")` y documentar completamente el .md. diff --git a/.claude/rules/tag_launcher.md b/.claude/rules/tag_launcher.md new file mode 100644 index 00000000..d027e5e6 --- /dev/null +++ b/.claude/rules/tag_launcher.md @@ -0,0 +1,5 @@ +Los pipelines con tag `launcher` aparecen en el Pipeline Launcher TUI (`apps/pipeline_launcher`). + +Sin el tag, el pipeline no es lanzable desde la TUI. Añadir `launcher` al array `tags` del .md al crear un pipeline ejecutable desde el launcher. + +Pipelines interactivos (TUIs) o que no son subprocesos NO deben llevar este tag. diff --git a/.claude/rules/types_in_signatures.md b/.claude/rules/types_in_signatures.md new file mode 100644 index 00000000..595d469b --- /dev/null +++ b/.claude/rules/types_in_signatures.md @@ -0,0 +1,3 @@ +Usar tipos nativos (float64, []float64, string) en firmas Go para evitar imports circulares entre paquetes de funciones. + +Documentar los tipos del registry en `uses_types`/`returns` del .md, no en la firma.