Files
motor-de-encuestas/sprints/sprint-1/ETAPA_1C_PROMPT.md

5.1 KiB

ETAPA 1C — Cierre de la fundación: REVOKE del GRANT peligroso + documentación

Prompt versionado (Patrón B.1). Cierra la auditoría de la Etapa 1B con el único cambio bloqueante que encontró y documenta tres decisiones que el agente tomó por iniciativa. Claude Code lo ejecuta tras leer CLAUDE.md, DATA_MODEL.md y este prompt.

1. Objetivo

Quitar el GRANT SELECT ON consent_records TO authenticated (puerta apoyada-sin-llave: hoy inerte, peligrosa si alguien suma una policy SELECT a futuro), confirmar en ejecución que no rompe el flujo de envío de la encuesta (la FK responses.consent_record_id), y documentar en DATA_MODEL.md tres decisiones tomadas en la 1B.

2. Contexto previo

La 1B aplicó las migraciones 001-006 a Supabase Cloud y la auditoría aprobó la fundación de datos salvo este punto. La migración 006 ya está aplicada en CloudNO se edita (rompería el historial de migraciones). El cambio va en una migración nueva, 007.

3. Decisiones ya tomadas (no consultar de nuevo)

  • El cambio es un REVOKE, en migración nueva 007. NO editar 001-006.
  • El GRANT INSERT ON consent_records TO anon, authenticated se mantiene (el envío del formulario lo necesita). Solo se revoca el SELECT.
  • NO se agrega ninguna policy SELECT a consent_records. El analyst lee vía service_role (que bypassa RLS y no necesita GRANTs).
  • No se toca el resto del esquema, ni las policies, ni service_role.

4. Tareas

  1. Crear la migración con supabase migration new revoke_consent_select y poner como contenido:
    -- 007: Revoca el SELECT sobre consent_records a authenticated.
    -- Auditoría 1B: GRANT inerte hoy (no hay policy SELECT) pero peligroso si a futuro alguien
    -- agrega una policy SELECT para org_admin → expondría quién consintió qué, vector de
    -- correlación con respuestas en encuesta anónima. El analyst lee vía service_role.
    REVOKE SELECT ON public.consent_records FROM authenticated;
    
  2. Aplicar a Cloud: supabase db push (usar npx supabase ... si el CLI no es global).
  3. Correr las validaciones de la sección 6 contra la base real.
  4. Documentar en DATA_MODEL.md las tres decisiones (texto exacto en la sección 5 de este prompt).

5. Texto EXACTO a agregar al final de DATA_MODEL.md (sección nueva)

## Decisiones ratificadas en ejecución (Sprint 1)
- **`options` en preguntas `rating` (F3, G4):** se guarda como objeto
  `{"min":1,"max":5,"min_label":"...","max_label":"..."}`, NO como array. El frontend (Sprint 2)
  debe manejar dos formas de `options`: array para `single_choice`/`multiple_choice`, objeto para
  `rating`.
- **`required = false` en todas las preguntas seeded:** la obligatoriedad real se define en Sprint 2
  (validación del formulario). Nota: B1 estaba marcada obligatoria en el mockup; revisar al construir
  el formulario.
- **Policies de `org_admin` presentes pero inertes en v1:** las policies RLS para `org_admin`
  (acceso multi-tenant por empresa) existen en migración 003, pero v1 NO tiene login de cliente
  ("nosotros presentamos a cada empresa"). El acceso real lo hace el analyst vía `service_role`. El
  camino `org_admin` queda reservado para un futuro de auto-servicio, no operado en v1.

6. Validaciones automatizadas mandatorias (contra la base Cloud)

La central es la #1 — confirma que revocar el SELECT NO rompe el envío:

  • FK intacta: simulando rol anon (SET ROLE anon + claims, o vía anon key), INSERT en consent_records → obtener su id → INSERT en responses referenciando ese consent_record_id (con survey_id de una encuesta status='live' y respondent_id NULL) → debe insertar sin error. Esto prueba que la verificación de FK no requiere SELECT sobre consent_records.
  • REVOKE efectivo: como authenticated, SELECT FROM consent_records → ahora "permission denied" (ya no "0 filas"). Confirma que el revoke aplicó.
  • Sin regresión: re-correr las claves de la 1B → RLS sobre responses/answers = 0 filas para org_admin; agg_segment n=3 → suprimido, n=5 → valor; inmutabilidad de consent_records (UPDATE/ DELETE → error) sigue vigente.
  • Si CUALQUIERA falla: NO declarar lista la etapa. Reportar y esperar. En especial, si la #1 fallara (la FK SÍ necesitaba el SELECT), detenerse y reportar — sería el caso que invalida el cambio.

7. Qué reportar

  • Verificado: salida concreta de cada validación (el INSERT anónimo que efectivamente insertó, el "permission denied" del SELECT como authenticated, y las 3 de no-regresión).
  • Asumido / Hallazgos / Decisiones por iniciativa (clasificadas por nivel).
  • git diff --name-only HEAD: debe contener solo la migración 007 nueva + DATA_MODEL.md.

8. Qué NO hacer

  • NO editar las migraciones 001-006 (006 ya está en Cloud).
  • NO agregar policy SELECT a consent_records.
  • NO tocar service_role, ni las policies de org_admin, ni el resto del esquema.
  • NO usar respondent_id ni exponer texto libre.
  • Ante conflicto entre una restricción y "que aplique limpio": detenerse y reportar, no resolver unilateralmente.