Doobie y composición de acceso a DB en 1 transacción

Doobie book dice que es una buena práctica devolver ConnectionIO desde su capa de repositorio. Ofrece la capacidad de encadenar llamadas y realizarlas en una sola transacción. Agradable y claro.

Ahora imaginemos que estamos trabajando en el servicio API REST y nuestro escenario es:

Encontrar un objeto en la base de datos Realice alguna manipulación asíncrona (utilizando cats.effect.IO o monix.eval.Task) con este objeto. Almacene el objeto en la base de datos.

Y queremos realizar todos estos pasos dentro de 1 transacción. El problema es que sin la transformación natural que nos brindatransactor.trans() estamos trabajando dentro de 2 mónadas -Task yConnectionIO. Eso no es posible

La pregunta es: cómo mezclar doobieConnectionIO con algún efecto mónada en 1 composición, como si estuviéramos trabajando en 1 transacción y pudiéramos comprometer / revertir todas las mutaciones de DB en el fin del mundo?

¡Gracias

UPD: pequeño ejemplo

def getObject: ConnectionIO[Request]                      = ???
def saveObject(obj: Request): ConnectionIO[Request]       = ???
def processObject(obj: Request): monix.eval.Task[Request] = ???

val transaction:??? = for {
    obj       <- getObject             //ConnectionIO[Request]
    processed <- processObject(obj)    //monix.eval.Task[Request]
    updated   <- saveObject(processed) //ConnectionIO[Request]
  } yield updated

UPD2: La respuesta correcta proporcionada por @ oleg-pyzhcov es elevar sus tipos de datos de efectos aConnectionIO Me gusta esto

def getObject: ConnectionIO[Request]                      = ???
def saveObject(obj: Request): ConnectionIO[Request]       = ???
def processObject(obj: Request): monix.eval.Task[Request] = ???

val transaction: ConnectionIO[Request] = for {
    obj       <- getObject                                           //ConnectionIO[Request]
    processed <- Async[ConnectionIO].liftIO(processObject(obj).toIO) //ConnectionIO[Request]
    updated   <- saveObject(processed)                               //ConnectionIO[Request]
} yield updated
val result: Task[Request] = transaction.transact(xa)

Respuestas a la pregunta(1)

Su respuesta a la pregunta