Estructura del método + fundación de datos Sprint 1 (pre-ejecución)

This commit is contained in:
markosbenitez
2026-06-02 07:21:49 -03:00
parent ef9e4bf998
commit e116e59ee9
11 changed files with 242 additions and 1 deletions

54
sprints/sprint-1/BRIEF.md Normal file
View File

@@ -0,0 +1,54 @@
# BRIEF — Sprint 1: Fundación de datos
> Brief versionado. Arranca antes de pedirle código al agente (Patrón A.1). El detalle ejecutable de
> cada etapa va en `ETAPA_X_PROMPT.md`.
---
## Objetivo (una frase)
Tener el modelo de datos de la plataforma implementado en Supabase — esquema + RLS + seed de la
encuesta de mapeo de cuidadores — como base verificable sobre la que después se montan formulario,
dashboard y wizard.
## Por qué este sprint primero
Todo lo demás (formulario, dashboard, wizard) escribe o lee de este modelo. Un modelo con datos
sensibles mal diseñado no se migra gratis. Empezamos por el contrato de datos (ADR-001 + DATA_MODEL).
## Alcance (qué entra)
1. Migraciones de Supabase para las tablas de `DATA_MODEL.md`.
2. Policies de RLS según la "Intención de RLS" de `DATA_MODEL.md`.
3. Constraint/trigger que rechaza `respondent_id` no nulo cuando `is_anonymous = true`.
4. Función `agg_segment(...)` que suprime celdas con `count < k_threshold`.
5. Tablas de consentimiento (`consent_versions`, `consent_records`) inmutables.
6. Seed: la encuesta de mapeo de cuidadores (preguntas B1/C1/D1 con lógica condicional, H1 con
límite, escalas, texto libre) cargada como `survey` + `questions` + reglas condicionales.
7. Seed de 1 organización de prueba.
## Fuera de alcance (explícito)
- Frontend del formulario (Sprint 2).
- Dashboard / reportes (Sprint 3).
- Wizard de creación de encuestas (post-validación del caso fijo).
- Integración LLM (BACKLOG).
- Modo B / `controller_role` dual (reservado en esquema, no operado).
- `respondent_id` en uso (reservado, va NULL).
- Decisión de residencia de datos (ADR-002 abierto; v1 puede correr en Cloud con datos de prueba).
## Decisiones ya tomadas (no renegociar — ver CLAUDE.md y ADR-001)
- Encuestas anónimas a nivel respondente; se conserva `company_id` + cuasi-identificadores.
- Dedup por `ip_hash`. Cuasi-identificadores en bucket (rango etario, no fecha exacta).
- Modo A. Consentimiento granular versionado inmutable. Umbral k = 5.
- El texto libre no se expone crudo a la capa analítica.
## Criterios de éxito (checklist)
- [ ] `supabase db reset` / migraciones aplican limpio desde cero.
- [ ] El esquema generado coincide con `DATA_MODEL.md` (todas las tablas y columnas).
- [ ] Test de RLS: una organización NO puede leer filas crudas de otra (ni de la suya).
- [ ] Test: `INSERT` con `respondent_id` no nulo en encuesta anónima → falla.
- [ ] Test: `agg_segment` devuelve "n insuficiente" para un segmento con count < 5.
- [ ] Test: `UPDATE`/`DELETE` sobre `consent_records` → falla (inmutabilidad).
- [ ] Seed carga la encuesta de cuidadores con sus reglas condicionales íntegras.
- [ ] El director revisa el esquema generado (no solo "tests verdes").
## Etapas del sprint
- **Etapa 1** — Esquema + RLS + constraints + seed (este prompt: `ETAPA_1_PROMPT.md`).
- (Etapa 2+ se definen tras validar la Etapa 1.)

View File

@@ -0,0 +1,65 @@
# ETAPA 1B — Corrección del seed + ejecución/validación real
> Prompt versionado (Patrón B.1). Cierra los huecos que la auditoría encontró en la Etapa 1: seed
> inventado/incompleto y nada ejecutado. Claude Code lo ejecuta tras leer `CLAUDE.md`, `DATA_MODEL.md`,
> `SEED_SPEC.md` y este prompt.
## 1. Objetivo
Reescribir `supabase/seed.sql` para que refleje el instrumento real (34 preguntas) según
`SEED_SPEC.md`, y ejecutar la base contra el proyecto **Supabase Cloud** ya vinculado (sin Docker)
para verificar de verdad lo que la Etapa 1 dejó sin correr.
## 2. Contexto previo
La Etapa 1 creó esquema, RLS, triggers, `agg_segment` y un seed **incorrecto** (9 de 34 preguntas;
B1/C1/D1 tipadas como `yes_no`; supuesto inválido C1→G4; D1 sin reglas; falta Sección A). El esquema
NO se ejecutó (no había Docker). Ahora hay un proyecto Supabase Cloud vinculado (`supabase link`).
## 3. Decisiones ya tomadas (no consultar de nuevo)
- Las 34 preguntas, tipos, opciones y condicionales están en `SEED_SPEC.md` — es el contrato.
- `conditional_rules` van en la pregunta **dependiente** (`{if_question, op:'eq', value:'Sí', action:'show'}`).
- B1/C1/D1 = `single_choice` de 3 opciones; solo "Sí" dispara el bloque.
- `is_sensitive=true` en las preguntas marcadas en `SEED_SPEC.md`. Encuesta = `sensible`, anónima, Modo A.
- `qi_age_bucket`←A2, `qi_sector`←A1, `qi_zone`=NULL (no se pregunta zona).
- `respondent_id` sigue NULL (encuesta anónima).
## 4. Tareas
1. Reescribir `supabase/seed.sql`: 1 organización demo, 1 `consent_version` v1 (scopes
`["operativo","macro_n1"]`), 1 `survey` (anónima/sensible/confidencial/Modo A/k=5), y las **34
preguntas** con sus tipos, opciones, `max_select` (H1=3), `is_sensitive`, y `conditional_rules`
en las dependientes (B2-B5, C2-C5, D2-D5).
2. Aplicar a Cloud: `supabase db push` y luego cargar el seed contra el proyecto vinculado.
3. Ejecutar las validaciones de la sección 6 contra la base real.
## 5. Definition of Done
- [ ] `seed.sql` con 34 preguntas que coinciden 1:1 con `SEED_SPEC.md`.
- [ ] `supabase db push` aplica limpio en Cloud (reportar si algún GRANT/policy falla — la auditoría sospechaba de 003/006).
- [ ] Seed cargado y consultable en el proyecto Cloud.
- [ ] Validaciones de la sección 6 verdes.
- [ ] `git diff --name-only HEAD` solo con `supabase/seed.sql` (+ tests si los tocás).
## 6. Validaciones automatizadas mandatorias (contra la base Cloud)
- Conteo: `SELECT count(*) FROM questions` = **34**; condicionales = **12** (B2-B5, C2-C5, D2-D5),
cada una con `if_question` correcto y `value='Sí'`.
- Tipos: B1/C1/D1 son `single_choice` (no `yes_no`); H1 `multiple_choice` con `max_select=3`;
F3/G4 `rating`; H3 `text_long`.
- `is_sensitive=true` en exactamente las preguntas marcadas en `SEED_SPEC.md`.
- RLS: como rol de organización, `SELECT * FROM responses` y `FROM answers`**0 filas**.
- Constraint: `INSERT` en `responses` con `respondent_id` no nulo en encuesta anónima → ERROR.
- k-anonimato: `agg_segment` sobre un segmento sembrado con 3 respuestas → "n insuficiente"; con ≥5 → valor.
- Inmutabilidad: `UPDATE`/`DELETE` sobre `consent_records` → ERROR.
- Si CUALQUIERA falla: **NO declarar lista la etapa.** Reportar el fallo y esperar instrucciones.
## 7. Qué reportar
- **Verificado:** salida concreta de cada validación (conteos, resultado de `agg_segment` n=3 y n=5,
comportamiento de RLS, errores esperados que efectivamente saltaron).
- **Asumido:** cualquier supuesto (ej. textos exactos de opciones que hayas normalizado).
- **Hallazgos no esperados** y **Decisiones por iniciativa** (clasificadas por nivel).
- **`git diff --name-only HEAD`** pegado.
## 8. Qué NO hacer
- NO tocar el esquema (migraciones 001-006) salvo que una validación revele un bug — y si lo revela,
**reportar antes de corregir** (cambiar esquema es Nivel 3 si toca RLS/privacidad).
- NO agregar columnas `qi_gender`/`qi_modality` (hay un hallazgo abierto en `SEED_SPEC.md` para el
director — es decisión Nivel 3, no la tomes acá).
- NO exponer texto libre (H3) en ninguna vista/función analítica.
- NO usar `respondent_id`. NO usar `service_role` en nada de cara al cliente.

View File

@@ -0,0 +1,79 @@
# ETAPA 1 — Fundación de datos (esquema + RLS + seed)
> Prompt versionado (Patrón B.1). Claude Code lo ejecuta tras leer `CLAUDE.md`, `ARCHITECTURE.md`,
> `DATA_MODEL.md`, `docs/adr/ADR-001-*` y `sprints/sprint-1/BRIEF.md`.
## 1. Objetivo
Implementar el modelo de datos completo en Supabase: migraciones, RLS, constraints de privacidad,
función de agregación con k-anonimato, tablas de consentimiento inmutables, y seed de la encuesta de
mapeo de cuidadores. Es la base verificable del producto.
## 2. Contexto previo
Proyecto nuevo. No hay esquema todavía. El contrato de datos está en `DATA_MODEL.md` y la
justificación de cada decisión de privacidad en `ADR-001`. Esta es la primera etapa de código del
proyecto; no hay deuda previa.
## 3. Decisiones ya tomadas (no consultar de nuevo)
- Encuestas anónimas a nivel respondente; `company_id` + cuasi-identificadores SE conservan.
- `respondent_id` reservado pero **NULL** (las 4 encuestas de v1 son anónimas).
- Dedup por `ip_hash`. Cuasi-identificadores en **bucket** (rango etario, no fecha exacta).
- Modo A (`controller_role = 'A'`). Consentimiento granular versionado **inmutable**.
- Umbral de k-anonimato default = 5 (`surveys.k_threshold`).
- Dos ejes de clasificación: `data_sensitivity` (legal) y `security_class` (seguridad), ortogonales.
- Stack: Supabase (Postgres + RLS). Migraciones SQL versionadas.
## 4. Tareas
1. Crear migraciones para todas las tablas de `DATA_MODEL.md` (`organizations`, `surveys`,
`questions`, `responses`, `answers`, `consent_versions`, `consent_records`) con tipos, FKs e
índices razonables.
2. Trigger/constraint: rechazar `INSERT`/`UPDATE` en `responses` con `respondent_id` no nulo cuando
la `survey` referida tiene `is_anonymous = true`.
3. Inmutabilidad de consentimiento: revocar/denegar `UPDATE` y `DELETE` sobre `consent_records` y
`consent_versions` (vía RLS o trigger).
4. Función `agg_segment(p_survey_id uuid, p_dimensions text[])`: agrega por las dimensiones pedidas y
**suprime** (devuelve marcador de "n insuficiente") toda celda con `count < k_threshold`.
5. Policies de RLS según "Intención de RLS" de `DATA_MODEL.md`: ninguna policy devuelve filas crudas
de `responses`/`answers` a un rol de organización; el acceso de organización es solo vía agregados
por encima del umbral.
6. Seed: cargar la encuesta de mapeo de cuidadores como `survey` (anónima, sensible, confidencial,
Modo A) + sus `questions` con códigos del mockup (B1/B2/B4/B5, C1, D1, G4, H1 con `max_select=3`,
H3 texto libre) + `conditional_rules` (B1/C1/D1 despliegan sus sub-preguntas). Cargar 1
`organization` de prueba y 1 `consent_version` v1 con scopes `["operativo","macro_n1"]`.
## 5. Entregables / Definition of Done
- [ ] Migraciones aplican limpio desde cero (`supabase db reset` o equivalente).
- [ ] Esquema coincide 1:1 con `DATA_MODEL.md`.
- [ ] Tests (ver sección 6) verdes.
- [ ] Seed cargado y consultable.
- [ ] `git diff --name-only HEAD` contiene solo archivos de migración/seed/test autorizados.
## 6. Validaciones automatizadas mandatorias (antes de entregar)
Correr y reportar resultado de cada una:
- `supabase db reset` (o migración desde cero) sin errores.
- Test RLS: como rol de `organization`, un `SELECT *` sobre `responses` de otra org devuelve 0 filas;
sobre la propia org también 0 filas crudas (solo agregados permitidos).
- Test constraint: `INSERT` en `responses` con `respondent_id` no nulo en encuesta anónima → ERROR.
- Test k-anonimato: `agg_segment` sobre un segmento sembrado con 3 respuestas → "n insuficiente";
con ≥5 → valor real.
- Test inmutabilidad: `UPDATE` y `DELETE` sobre `consent_records` → ERROR.
- Verificación de seed: la encuesta tiene todas las preguntas esperadas y las reglas condicionales
enlazan a las preguntas correctas (conteo concreto, no "se cargó bien").
- Si CUALQUIERA falla: **NO entregar**. Reportar el fallo y esperar instrucciones.
## 7. Qué reportar (formato)
- **Verificado:** resultado concreto de cada validación (nº de tablas, nº de tests, salida de
`agg_segment` para n=3 y n=5, conteo de preguntas y de reglas del seed).
- **Asumido:** cualquier supuesto tomado (ej. tipos de columna no especificados, nombres de roles).
- **Hallazgos no esperados:** lo que descubriste y merece decisión, aunque no esté en el DoD.
- **Decisiones por iniciativa:** clasificadas por nivel (ver política en `CLAUDE.md`).
- **`git diff --name-only HEAD`:** pegá la salida.
## 8. Qué NO hacer
- NO construir frontend, formulario ni dashboard (otras etapas).
- NO usar `respondent_id` (va NULL).
- NO implementar Modo B ni lógica dual de `controller_role`.
- NO exponer texto libre crudo en ninguna vista/función analítica.
- NO tocar nada de privacidad/anonimato/consentimiento de forma distinta a ADR-001 sin consultar
(es Nivel 3 siempre).
- Ante colisión entre una restricción y "build/tests limpios": **DETENERSE y reportar el conflicto**,
no resolver unilateralmente.