# CLAUDE.md — Reglas del proyecto

> Este archivo lo carga el agente (Claude Code) por defecto. Contiene lo que aplica a **TODO** el
> proyecto: reglas no negociables, decisiones ya tomadas, política de iniciativa y verificaciones
> pre-entrega. El agente NO puede re-decidir lo que está acá. (Patrón B.4.)

---

## Identidad del proyecto

Plataforma de encuestas con soberanía de datos. Caso fundacional: mapeo de cuidadores en empresas.
Objetivo macro: "economía de la discapacidad" en Paraguay. Trata **datos sensibles** (salud/
discapacidad) → la privacidad no es una feature, es una restricción de diseño.

---

## Reglas no negociables (datos y privacidad)

1. **Anonimato es por-encuesta**, no global. Cada encuesta declara su modo; el esquema y la lógica
   de guardado lo respetan. Nunca asumir anonimato por defecto ni quitarlo por conveniencia.
2. **En encuestas anónimas, NUNCA escribir una clave de individuo** (`respondent_id`) ni cookie de
   sesión linkeable. La deduplicación se hace con `ip_hash` (hash unidireccional + salt), nunca con
   identidad.
3. **El umbral de k-anonimato es mandatorio en toda visualización compartida.** Ninguna celda,
   gráfico o tabla expuesta a una empresa puede mostrar un segmento con **n < UMBRAL_K** (config del
   proyecto, default 5). Esto aplica AUNQUE la encuesta sea anónima.
4. **El texto libre NO entra al store analítico crudo.** Se excluye o se categoriza antes (es un
   vector de re-identificación). El gráfico/reporte trabaja sobre categorías, no sobre texto crudo.
5. **El consentimiento es evidencia, no UI.** Cada respuesta guarda un registro de consentimiento
   versionado, con timestamp, inmutable, contra la versión del texto vigente al momento. Cambiar el
   wording del consentimiento NO altera registros viejos. (Ver ADR-003.)
6. **La elección granular del titular (el respondente) siempre gana** sobre cualquier documento
   firmado por la empresa. La empresa autoriza el despliegue; el individuo consiente el tratamiento
   de su propio dato.
7. **Modo de responsable (`controller_role`) define el flujo de datos:**
   - **Modo A** (nosotros = responsable): el dato puede alimentar el macro a todos los niveles que el
     titular consintió.
   - **Modo B** (empresa = responsable, nosotros = encargado): el dato **solo** puede alimentar el
     macro vía **Nivel 1 anonimizado irreversible**. Nunca Nivel 2/3.
   - **v1 corre solo Modo A.** El campo existe pero la lógica dual no se construye todavía.
8. **La empresa nunca accede a dato individual crudo.** Solo recibe agregados/dashboards autorizados
   por encima del umbral. (Coherente con Modo A + k-anonimato.)
9. **Manejo de API keys de Supabase — transversal y crítico.** La `anon` key es pública y **respeta
   RLS**: es la única que puede tocar el frontend/cliente. La `service_role` key **bypassa RLS por
   completo** y por lo tanto saltea k-anonimato, consentimiento y todo el modelo de ADR-001. Reglas:
   - La `service_role` **NUNCA** va al frontend, al cliente, a un artefacto público ni a git. Solo
     vive server-side (Edge Functions / backend), cargada desde variable de entorno.
   - `.env` y `.env.*` siempre en `.gitignore`. Una `service_role` en el historial de git es un
     incidente de seguridad aunque el repo sea privado → rotar la key de inmediato.
   - Toda operación de cara al respondente o a la empresa usa `anon` key + RLS. Si algo "necesita"
     `service_role` para funcionar en el cliente, está mal diseñado: revisar las policies, no exponer
     la key.
10. **El flujo del respondente NUNCA se ata a un IdP / SSO.** Encuestas anónimas = sin login, sin
    Keycloak, sin cookie de sesión identificable. El SSO (Keycloak) es solo para staff interno. RLS
    lee claims por nombre (`org_id`, `role`) para que el emisor del token sea intercambiable; nunca
    basar RLS en `user_metadata` (modificable por el usuario). (Ver ADR-004.)

---

## Distinción que NO se puede volver a confundir: anónimo vs pseudónimo

- **Comparar segmentos** ("alguien de 25, sector X, zona A" vs "alguien de 25, sector X, zona B") se
  hace con los **cuasi-identificadores guardados en cada fila**. NO requiere `respondent_id`. Vive en
  datos 100% anónimos.
- **`respondent_id`** (clave pseudónima) sirve para vincular varias respuestas a la **misma persona
  desconocida** (longitudinal individual, re-contacto, dedup avanzado). **Nada de eso es caso de v1.**
- Por lo tanto: anónimo a nivel respondente **alcanza** para la comparación que el producto necesita.
  La comparación individuo-vs-individuo (n=1) está **prohibida** en dashboards compartidos.

---

## Política de iniciativa proactiva (clasificar antes de actuar)

Ante una mejora fuera del scope, el agente clasifica el impacto y actúa según el nivel. Evaluar en
este orden; el primero que aplique decide:

1. ¿Resuelve un ítem de `TECH_DEBT.md` / `BACKLOG.md` / planificación? → **Nivel 3**.
2. ¿Choca con restricción explícita del prompt ("NO entra", "NO tocar", "agendado para etapa Z")? → **Nivel 3**.
3. ¿Toca privacidad, anonimato, consentimiento, clasificación de datos o RLS? → **Nivel 3 SIEMPRE**.
4. ¿Modifica paginación, layout, cantidad de archivos o estructura de salida? → **Nivel 2 mínimo**.
5. ¿Es visible al usuario final (texto, color, posición, contenido)? → **Nivel 2 mínimo**.
6. ¿Afecta marca, identidad, dependencias o configuración? → **Nivel 3**.
7. Si nada aplica → **Nivel 1**.

- **Nivel 1** (interno, invisible, reversible): ejecutar; mencionar al final si fueron varios.
- **Nivel 2** (visible reversible): ejecutar **y reportar** como "decisión proactiva — validar/revertir".
- **Nivel 3** (marca/arquitectura/datos/privacidad): **NO ejecutar. Consultar antes** con el formato:
  ```
  PROPUESTA DE CAMBIO NIVEL 3 — requiere aprobación
  Cambio sugerido: [descripción]   Justificación: [por qué]   Impacto: [qué afecta]   Alternativa si se rechaza: [qué hacer]
  ```

Argumentos que NO bajan de nivel: "es legibilidad", "es consistencia", "es trivial de revertir",
"es un bug menor", "el usuario lo va a agradecer". Si está en TECH_DEBT/BACKLOG, es Nivel 3 sin
importar el tamaño técnico.

---

## Verificaciones obligatorias antes de entregar (toda etapa)

1. `git diff --name-only HEAD` → solo archivos autorizados por el prompt. Si aparece uno no
   autorizado: revertir (`git checkout HEAD -- <archivo>`), listar bajo "Conflictos de scope", no incluirlo.
2. Si una restricción del prompt (`NO tocar X`) colisiona con otro requisito (build limpio):
   **DETENERSE y reportar el conflicto**, no resolver unilateralmente.
3. Reporte con **datos concretos**, no descripciones ("PDF: 78 KB, 4 págs, tabla 11 filas",
   no "PDF generado correctamente").
4. Separar explícitamente **Verificado** vs **Asumido** vs **Hallazgos no esperados**.
5. Tests verdes **NO** es etapa terminada. Si hay artefacto visible, el humano lo abre (validación
   visual la hace el director, no el agente).

---

## Decisiones ya tomadas (no consultar de nuevo)

- Etapa 1 = una encuesta fija (mapeo cuidadores) multi-empresa. **NO** builder visual.
- Las 4 encuestas de v1: anónimas a nivel respondente + confidenciales (seguridad).
- Se conservan `company_id` + cuasi-identificadores. NO se usa `respondent_id`.
- Modo A (nosotros responsables). Sin Nivel 3 atribuible en esta etapa.
- Empresas actúan sobre agregados, nunca sobre individuos nombrados.
- Dedup por `ip_hash`. Consentimiento granular versionado e inmutable.
- Umbral de k-anonimato default = 5 (parametrizable por proyecto).
- Separador de miles y formato de cifras: **definir en `CONVENTIONS.md`** (ver Decisiones abiertas).

---

## Decisiones abiertas (requieren al director, no las cierra el agente)

- **Nombre/marca del producto** (Nivel 3).
- **Residencia de datos**: Supabase Cloud vs self-host (ADR-002).
- **`CONVENTIONS.md`**: formato de cifras, idioma de la UI, tono de los mensajes. Apenas una
  convención se pregunte 2 veces, documentarla acá (anti-patrón AP.4).