# Referencia Completa — Sistema de Instintos

## Hook de Observación Mínimo (Node.js)

```javascript
// hooks/observe-post.js
const fs = require('fs');

const input = JSON.parse(fs.readFileSync('/dev/stdin', 'utf8'));
const { tool_name, tool_input, tool_response } = input;

const event = {
  ts: Date.now(),
  tool: tool_name,
  success: !tool_response?.error,
  duration_ms: tool_response?.duration_ms ?? null,
  project: process.env.PROJECT_NAME ?? 'global',
};

// Append al log de observaciones
const logPath = process.env.OBSERVATIONS_LOG ?? '.claude/observations.jsonl';
fs.appendFileSync(logPath, JSON.stringify(event) + '\n');

// Exit 0 obligatorio — nunca bloquear el flujo
process.exit(0);
```

---

## Formato Completo de un Instinto

```yaml
---
id: instinto-20240315-001
titulo: "Siempre usar selectinload en queries con relaciones"
confianza: 0.75
scope: proyecto              # "proyecto" | "global"
proyecto: sigaf-backend      # solo si scope=proyecto
observaciones: 7             # cuántas veces se observó
primera_vez: "2024-03-10"
ultima_vez: "2024-03-15"
estado: activo               # "draft" | "activo" | "deprecado" | "promovido"
promovido_a: null            # "skill:fastapi-experto" | "comando:fix-selectin" | null
tags: [sqlalchemy, async, orm]
---

## Descripción

Al usar SQLAlchemy async, cada vez que se accede a una relación en la
serialización Pydantic sin `selectinload()` se produce `MissingGreenlet`.

## Patrón observado

En 7 sesiones de trabajo con el modelo `fastapi-experto`, se detectó que
queries sin eager loading causaban errores en producción que no aparecían
en tests síncronos.

## Acción correctiva

```python
# SIEMPRE incluir selectinload para relaciones accedidas
stmt = select(Modelo).options(selectinload(Modelo.relacion))
```

## Condiciones de activación

- Proyecto usa SQLAlchemy async (detectado en requirements.txt)
- Se están escribiendo endpoints FastAPI con Pydantic

## Evidencia

- Sesión 2024-03-10: error MissingGreenlet en endpoint /usuarios
- Sesión 2024-03-12: mismo error en endpoint /proyectos
- Sesión 2024-03-15: prevenido al aplicar selectinload preventivamente
```

---

## Scope de Dominio (v4.1)

Formato de instinto con scope dominio:

```yaml
---
scope: dominio
dominio: backend-python
condiciones_activacion:
  - "requirements.txt contiene fastapi"
  - "pyproject.toml contiene fastapi"
---
```

Dominios válidos (alineados con la tabla de habilidades del sistema):

| Dominio | Se activa cuando el proyecto contiene |
|---------|--------------------------------------|
| `backend-python` | requirements.txt/pyproject.toml con fastapi, django, flask |
| `backend-node` | package.json con express, fastify, nestjs |
| `frontend-react` | package.json con react, next |
| `frontend-angular` | package.json con @angular/core |
| `frontend-css` | archivos *.css, *.scss, tailwind.config.* |
| `mobile-android` | build.gradle con android, archivos *.kt |
| `mobile-ios` | *.xcodeproj, Package.swift, archivos *.swift |
| `mobile-cross` | package.json con react-native, pubspec.yaml con flutter |
| `datos` | archivos *.sql, dbt_project.yml, alembic/ |
| `infra` | archivos *.tf, docker-compose*, k8s/ |
| `seguridad` | auth/, security/, middleware/ |

---

## Reglas de Promoción de Scope

**Proyecto -> Dominio**: Un instinto de proyecto puede ascender a dominio si:
1. Se observa en 2+ proyectos distintos del mismo dominio
2. La confianza es >= 0.6 en ambos proyectos
3. La condición de activación es detectable automáticamente (archivo de config)

**Dominio -> Global**: Un instinto de dominio puede ascender a global si:
1. Se observa en 3+ dominios distintos con el mismo patrón
2. La confianza es >= 0.7 en todos los dominios
3. No contradice ningún instinto global existente

**Degradación**: Un instinto puede bajar de scope si es contradicho en un contexto
donde debería aplicar.

```bash
# Comando para promover scope
node scripts/instinto-promover-scope.js \
  --id instinto-20240315-001 \
  --de proyecto \
  --a dominio \
  --dominio backend-python
```

---

## Promoción de Instintos

### A Skill

Cuando un instinto tiene confianza >= 0.85 y cubre un dominio técnico bien definido:

```bash
# Genera un borrador de SKILL.md a partir del instinto
node scripts/instinto-a-skill.js \
  --instinto .claude/instintos/instinto-20240315-001.md \
  --skill-dir habilidades/selectinload-sqlalchemy/
```

El instinto se marca `estado: promovido` y `promovido_a: skill:selectinload-sqlalchemy`.

### A Comando

Cuando el instinto describe una acción repetitiva que puede automatizarse:

```bash
node scripts/instinto-a-comando.js \
  --instinto .claude/instintos/instinto-20240318-003.md \
  --comando-dir comandos/fix-missing-selectin/
```

### A Agente

Cuando el instinto describe un workflow completo y recurrente (confianza >= 0.90):

```bash
node scripts/instinto-a-agente.js \
  --instinto .claude/instintos/instinto-20240320-007.md \
  --agente-dir agentes/revisor-sqlalchemy/
```

---

## Evolución de Instintos

### Merge (fusión)

Dos instintos con patrones solapados se fusionan:

```yaml
# merge-plan.yaml
fuente_a: instinto-20240310-001   # "usar selectinload"
fuente_b: instinto-20240312-003   # "lazy='selectin' en relaciones Usuario"
resultado: instinto-20240320-010  # "estrategia completa de eager loading async"
razon: "Ambos instintos cubren el mismo dominio desde ángulos complementarios"
```

Regla: el instinto fusionado hereda `confianza = max(a, b) × 0.9` (penalty por fusión).

### Split (división)

Un instinto demasiado genérico se divide en instintos más específicos:

```yaml
# split-plan.yaml
fuente: instinto-20240301-001   # "buenas prácticas SQLAlchemy"
resultados:
  - instinto-20240320-011       # "eager loading en queries async"
  - instinto-20240320-012       # "session management en endpoints"
  - instinto-20240320-013       # "commit solo en endpoint, nunca en service"
razon: "El instinto original era demasiado amplio para activación precisa"
```

### Deprecate (deprecación)

Un instinto se depreca cuando:
- La librería cambió y el patrón ya no aplica
- Se encontró una mejor práctica que lo reemplaza
- La confianza cayó por debajo de 0.2 tras múltiples refutaciones

```yaml
estado: deprecado
deprecado_en: "2024-04-01"
razon: "SQLAlchemy 2.1 agregó lazy loading seguro en async por defecto"
reemplazado_por: instinto-20240401-020
```

---

## Protección contra Contaminación Cross-Proyecto

### El problema

Si los instintos de un proyecto contaminan otro proyecto, se generan
sugerencias incorrectas. Ejemplo: el prefijo `tb_` de tablas de un proyecto
legacy no debe aplicarse en un proyecto nuevo con convención `snake_case`.

### Mecanismo de aislamiento

```javascript
// hooks/instinto-loader.js
const projectName = process.env.PROJECT_NAME;
const instintosGlobales = loadInstintos('~/.claude/instintos/');
const instintosProyecto = loadInstintos(`.claude/instintos/`);

// Los instintos de proyecto NUNCA se exportan a otros proyectos
const instintosActivos = [
  ...instintosGlobales.filter(i => i.scope === 'global'),
  ...instintosProyecto.filter(i => i.proyecto === projectName),
];
```

### Cuarentena de instintos sospechosos

Cuando un instinto produce una sugerencia que el humano rechaza 3+ veces,
entra en cuarentena automática:

```yaml
estado: cuarentena
cuarentena_inicio: "2024-03-20"
rechazos: 3
cuarentena_fin: "2024-03-27"   # revisión en 7 días
```

Durante la cuarentena, el instinto no se activa pero tampoco se borra —
se espera revisión humana.

---

## Directorio de Instintos

Estructura recomendada en el proyecto:

```
.claude/
└── instintos/
    ├── index.yaml           # índice de todos los instintos activos
    ├── draft/               # instintos con confianza < 0.5
    ├── activos/             # instintos con confianza >= 0.5
    ├── cuarentena/          # instintos rechazados en revisión
    └── promovidos/          # instintos ya convertidos a skill/cmd/agente
```

### index.yaml mínimo

```yaml
version: 2
ultimo_update: "2024-03-20"
totales:
  draft: 3
  activos: 12
  cuarentena: 1
  promovidos: 5
instintos:
  - id: instinto-20240315-001
    titulo: "Siempre usar selectinload en queries con relaciones"
    confianza: 0.75
    scope: proyecto
    estado: activo
```
