package services import ( "os" "strings" "testing" ) // La regla de aprobación es lo que separa un asistente de una máquina de spam // con el dominio del cliente. Si alguien la afloja, esto tiene que fallar. func TestRequiereAprobacion(t *testing.T) { casos := []struct { nombre string interna bool tool string requiere bool }{ // Canal público: cualquiera escribe. Todo lo que sale, espera. {"público no puede mandar correo", false, "enviar_correo", true}, {"público no puede llamar una herramienta", false, "avisar_stock", true}, {"público no puede generar documentos", false, "generar_documento", true}, // Leer no saca nada del negocio. {"público sí puede buscar en el conocimiento", false, "buscar_conocimiento", false}, {"público sí puede leer la bandeja", false, "leer_bandeja", false}, // Canal interno: el dueño ya autorizó al escribirlo. Mandarlo a // aprobar su propio pedido es fricción sin seguridad. {"el dueño manda correo directo", true, "enviar_correo", false}, {"el dueño ejecuta herramientas directo", true, "avisar_stock", false}, } for _, c := range casos { if got := RequiereAprobacion(c.interna, c.tool); got != c.requiere { t.Errorf("%s: RequiereAprobacion(interna=%v, %q) = %v, quiero %v", c.nombre, c.interna, c.tool, got, c.requiere) } } } // Lo que el modelo le cuenta al cliente cuando algo queda esperando no puede // filtrar la cocina del negocio. func TestEncolarNoFiltraElProcesoInterno(t *testing.T) { b, err := os.ReadFile("umind_aprobacion_service.go") if err != nil { t.Fatal(err) } s := string(b) i := strings.Index(s, "func EncolarAccion") j := strings.Index(s[i:], "\nfunc ") cuerpo := s[i : i+j] nota := cuerpo[strings.Index(cuerpo, `"nota":`):] nota = nota[:strings.Index(nota, "\n")] for _, prohibido := range []string{"rechaz", "aprobación interna"} { if strings.Contains(strings.ToLower(nota), prohibido) { t.Errorf("la nota al cliente menciona %q: %s", prohibido, nota) } } if !strings.Contains(strings.ToLower(nota), "sin mencionar") { t.Error("la nota tiene que instruir al modelo a no mencionar el proceso interno") } } // El payload se ejecuta tal cual se aprobó: si al aprobar se le volviera a // preguntar al modelo, se aprobaría una cosa y saldría otra. func TestAccionAprobadaUsaElPayloadGuardado(t *testing.T) { b, err := os.ReadFile("umind_aprobacion_service.go") if err != nil { t.Fatal(err) } s := string(b) i := strings.Index(s, "func EjecutarAccionAprobada") j := strings.Index(s[i:], "\n// avisarAccionPendiente") cuerpo := s[i : i+j] if !strings.Contains(cuerpo, "accion.ArgumentosJSON") { t.Error("la ejecución tiene que partir de los argumentos guardados") } if strings.Contains(cuerpo, "callAI") || strings.Contains(cuerpo, "ProcessWidgetMessage") { t.Error("aprobar no puede volver a llamar al modelo: se aprobaría una cosa y saldría otra") } // Dos personas mirando la misma bandeja pueden aprobar a la vez. if !strings.Contains(cuerpo, "ReclamarAccion") { t.Error("falta el reclamo: sin él, dos aprobaciones simultáneas ejecutan dos veces") } }