Repository: 7mind/izumi
Pull request #939 (2020-03-12 14:05:02)

Bundled containers for ZK, Kafka, C*
Issues:
#936 
#935

codecov-io: # [Codecov](https://codecov.io/gh/7mind/izumi/pull/939?src=pr&el=h1) Report
> Merging [#939](https://codecov.io/gh/7mind/izumi/pull/939?src=pr&el=desc) into [develop](https://codecov.io/gh/7mind/izumi/commit/132db37b5ae60f791baf45cea32a8f880b36fa9a?src=pr&el=desc) will **decrease** coverage by `0.29%`.
> The diff coverage is `0%`.

[![Impacted file tree graph](https://codecov.io/gh/7mind/izumi/pull/939/graphs/tree.svg?width=650&token=77pa3UU1Je&height=150&src=pr)](https://codecov.io/gh/7mind/izumi/pull/939?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           develop     #939     +/-   ##
==========================================
- Coverage    58.21%   57.91%   -0.3%     
==========================================
  Files          352      355      +3     
  Lines         7658     7685     +27     
  Branches       476      449     -27     
==========================================
- Hits          4458     4451      -7     
- Misses        3200     3234     +34
```


| [Impacted Files](https://codecov.io/gh/7mind/izumi/pull/939?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [...zumi/distage/docker/examples/CassandraDocker.scala](https://codecov.io/gh/7mind/izumi/pull/939/diff?src=pr&el=tree#diff-ZGlzdGFnZS9kaXN0YWdlLWZyYW1ld29yay1kb2NrZXIvc3JjL21haW4vc2NhbGEvaXp1bWkvZGlzdGFnZS9kb2NrZXIvZXhhbXBsZXMvQ2Fzc2FuZHJhRG9ja2VyLnNjYWxh) | `0% <0%> (ø)` | |
| [...umi/distage/docker/examples/ZookkeeperDocker.scala](https://codecov.io/gh/7mind/izumi/pull/939/diff?src=pr&el=tree#diff-ZGlzdGFnZS9kaXN0YWdlLWZyYW1ld29yay1kb2NrZXIvc3JjL21haW4vc2NhbGEvaXp1bWkvZGlzdGFnZS9kb2NrZXIvZXhhbXBsZXMvWm9va2tlZXBlckRvY2tlci5zY2FsYQ==) | `0% <0%> (ø)` | |
| [...la/izumi/distage/docker/examples/KafkaDocker.scala](https://codecov.io/gh/7mind/izumi/pull/939/diff?src=pr&el=tree#diff-ZGlzdGFnZS9kaXN0YWdlLWZyYW1ld29yay1kb2NrZXIvc3JjL21haW4vc2NhbGEvaXp1bWkvZGlzdGFnZS9kb2NrZXIvZXhhbXBsZXMvS2Fma2FEb2NrZXIuc2NhbGE=) | `0% <0%> (ø)` | |
| [...rc/main/scala/org/scalatest/SafeTestReporter.scala](https://codecov.io/gh/7mind/izumi/pull/939/diff?src=pr&el=tree#diff-ZGlzdGFnZS9kaXN0YWdlLXRlc3RraXQtc2NhbGF0ZXN0L3NyYy9tYWluL3NjYWxhL29yZy9zY2FsYXRlc3QvU2FmZVRlc3RSZXBvcnRlci5zY2FsYQ==) | `78.94% <0%> (-13.16%)` | :arrow_down: |
| [...izumi/fundamentals/platform/language/IzScala.scala](https://codecov.io/gh/7mind/izumi/pull/939/diff?src=pr&el=tree#diff-ZnVuZGFtZW50YWxzL2Z1bmRhbWVudGFscy1wbGF0Zm9ybS9zcmMvbWFpbi9zY2FsYS9penVtaS9mdW5kYW1lbnRhbHMvcGxhdGZvcm0vbGFuZ3VhZ2UvSXpTY2FsYS5zY2FsYQ==) | `55.55% <0%> (-11.12%)` | :arrow_down: |
| [...mentals/reflection/macrortti/LightTypeTagRef.scala](https://codecov.io/gh/7mind/izumi/pull/939/diff?src=pr&el=tree#diff-ZnVuZGFtZW50YWxzL2Z1bmRhbWVudGFscy1yZWZsZWN0aW9uL3NyYy9tYWluL3NjYWxhL2l6dW1pL2Z1bmRhbWVudGFscy9yZWZsZWN0aW9uL21hY3JvcnR0aS9MaWdodFR5cGVUYWdSZWYuc2NhbGE=) | `68.6% <0%> (-1.17%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/7mind/izumi/pull/939?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/7mind/izumi/pull/939?src=pr&el=footer). Last update [132db37...746fb93](https://codecov.io/gh/7mind/izumi/pull/939?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

0lejk4: I may be incorrect but isn't such Kafka/Zookeeper setup disallows creation of multiple containers? Because you assign zookeeper container a name there can be only one instance with same name. And as far as I know in one zookeeper instance there can only be one Kafka instance. The second one you'll try to start will fail.
Caparow: @0lejk4 I've updated the solution.
Now each run will be created new random ZK and Kafka (under one network since containers linked to each other by names). 
But, I do not understand why you want to use an independent container for each test if you could use random topics (or ZK directories if you are using it directly). Also, with DI we are binding singletons, if you want multiple independent containers you should bind them with different `DIKey`s.
E.g. 
```scala
make[KafkaDocker.Conteiner].named("test-kafka-1").fromResource{...}
```

Please, @neko-kai correct me if I am wrong. Also, I don't quite like current bindings, but I cannot combine `ProviderMagnets` to use this like this `(zk: Zookeeper) => new Kafka(zk).make[F]` (it will return ProviderMagnet[ProviderMagnet[...]). 

Patch:
diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml
index 01942e43f..bb732b59b 100644
--- a/.azure-pipelines.yml
+++ b/.azure-pipelines.yml
@@ -1,5 +1,10 @@
 # https://aka.ms/yaml
 
+pr:
+  branches:
+    include:
+    - '*'
+
 trigger:
   tags:
     include:
diff --git a/README.md b/README.md
index a73e1a289..2b9643ab0 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 [![Gitter](https://badges.gitter.im/7mind/izumi.svg)](https://gitter.im/7mind/izumi)
 [![Patreon](https://img.shields.io/badge/patreon-sponsor-ff69b4.svg)](https://www.patreon.com/7mind)
-[![Build Status](https://dev.azure.com/7mind/izumi/_apis/build/status/7mind.izumi?branchName=develop)](https://dev.azure.com/7mind/izumi/_build/latest?definitionId=3&branchName=develop)
+[![Build Status](https://dev.azure.com/7mind/izumi/_apis/build/status/7mind.izumi?branchName=develop)](https://dev.azure.com/7mind/izumi/_build/latest?definitionId=7&branchName=develop)
 [![codecov](https://codecov.io/gh/7mind/izumi/branch/develop/graph/badge.svg)](https://codecov.io/gh/7mind/izumi)
 [![CodeFactor](https://www.codefactor.io/repository/github/7mind/izumi/badge)](https://www.codefactor.io/repository/github/7mind/izumi)
 [![License](https://img.shields.io/github/license/7mind/izumi.svg)](https://github.com/7mind/izumi/blob/develop/LICENSE)
diff --git a/build.sbt b/build.sbt
index 609d31285..5b274fdd7 100644
--- a/build.sbt
+++ b/build.sbt
@@ -629,7 +629,8 @@ lazy val `fundamentals-json-circe` = project.in(file("fundamentals/fundamentals-
       "io.circe" %% "circe-parser" % V.circe,
       "io.circe" %% "circe-literal" % V.circe,
       "io.circe" %% "circe-generic-extras" % V.circe_generic_extras,
-      "io.circe" %% "circe-derivation" % V.circe_derivation
+      "io.circe" %% "circe-derivation" % V.circe_derivation,
+      "org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided
     )
   )
   .settings(
@@ -1034,6 +1035,7 @@ lazy val `distage-extension-config` = project.in(file("distage/distage-extension
       "org.scala-lang.modules" %% "scala-collection-compat" % V.collection_compat,
       "org.scalatest" %% "scalatest" % V.scalatest % Test,
       "com.github.pureconfig" %% "pureconfig-magnolia" % V.pureconfig,
+      "com.propensive" %% "magnolia" % V.magnolia,
       "org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided
     )
   )
@@ -1756,6 +1758,7 @@ lazy val `distage-testkit-scalatest` = project.in(file("distage/distage-testkit-
       "org.typelevel" %% "cats-core" % V.cats % Optional,
       "org.typelevel" %% "cats-effect" % V.cats_effect % Optional,
       "dev.zio" %% "zio" % V.zio % Optional,
+      "org.scalamock" %% "scalamock" % V.scalamock % Test,
       "org.scalatest" %% "scalatest" % V.scalatest
     )
   )
diff --git a/distage/distage-core-api/.js/src/main/scala/izumi/distage/model/reflection/MirrorProvider.scala b/distage/distage-core-api/.js/src/main/scala/izumi/distage/model/reflection/MirrorProvider.scala
index e157f5fe3..2c043f122 100644
--- a/distage/distage-core-api/.js/src/main/scala/izumi/distage/model/reflection/MirrorProvider.scala
+++ b/distage/distage-core-api/.js/src/main/scala/izumi/distage/model/reflection/MirrorProvider.scala
@@ -1,6 +1,6 @@
 package izumi.distage.model.reflection
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.SafeType
+import izumi.distage.model.reflection.SafeType
 import izumi.fundamentals.reflection.TypeUtil
 
 trait MirrorProvider {
diff --git a/distage/distage-core-api/.jvm/src/main/scala/izumi/distage/model/reflection/MirrorProvider.scala b/distage/distage-core-api/.jvm/src/main/scala/izumi/distage/model/reflection/MirrorProvider.scala
index dab6555c6..1dfe7ca47 100644
--- a/distage/distage-core-api/.jvm/src/main/scala/izumi/distage/model/reflection/MirrorProvider.scala
+++ b/distage/distage-core-api/.jvm/src/main/scala/izumi/distage/model/reflection/MirrorProvider.scala
@@ -2,7 +2,6 @@ package izumi.distage.model.reflection
 
 import java.lang.reflect.Modifier
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.SafeType
 import izumi.fundamentals.reflection.TypeUtil
 
 trait MirrorProvider {
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/AbstractLocator.scala b/distage/distage-core-api/src/main/scala/izumi/distage/AbstractLocator.scala
index dd39e233a..fdee7c7c4 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/AbstractLocator.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/AbstractLocator.scala
@@ -2,7 +2,7 @@ package izumi.distage
 
 import izumi.distage.model.Locator
 import izumi.distage.model.exceptions.MissingInstanceException
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.fundamentals.reflection.Tags.Tag
 
 trait AbstractLocator extends Locator {
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/constructors/constructors.scala b/distage/distage-core-api/src/main/scala/izumi/distage/constructors/constructors.scala
index 420d84da9..d7ac58a1d 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/constructors/constructors.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/constructors/constructors.scala
@@ -4,32 +4,30 @@ import izumi.distage.constructors.macros._
 import izumi.distage.model.definition.dsl.ModuleDefDSL
 import izumi.distage.model.exceptions.{TraitInitializationFailedException, UnsupportedDefinitionException}
 import izumi.distage.model.providers.ProviderMagnet
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.SafeType
+import izumi.distage.model.reflection.SafeType
 import izumi.fundamentals.reflection.Tags.WeakTag
 
 import scala.language.experimental.{macros => enableMacros}
 
-sealed trait AnyConstructor[T] extends AnyConstructorOptionalMakeDSL[T] {
-  def provider: ProviderMagnet[T]
-}
-final case class ClassConstructor[T](provider: ProviderMagnet[T]) extends AnyConstructor[T]
-final case class TraitConstructor[T](provider: ProviderMagnet[T]) extends AnyConstructor[T]
-final case class FactoryConstructor[T](provider: ProviderMagnet[T]) extends AnyConstructor[T]
+sealed trait AnyConstructor[T] extends Any with AnyConstructorOptionalMakeDSL[T]
+final class ClassConstructor[T](val provider: ProviderMagnet[T]) extends AnyVal with AnyConstructor[T]
+final class TraitConstructor[T](val provider: ProviderMagnet[T]) extends AnyVal with AnyConstructor[T]
+final class FactoryConstructor[T](val provider: ProviderMagnet[T]) extends AnyVal with AnyConstructor[T]
 
 object AnyConstructor {
-  def apply[T: AnyConstructor]: AnyConstructor[T] = implicitly
+  def apply[T](implicit ctor: AnyConstructor[T]): ProviderMagnet[T] = ctor.provider
 
   implicit def materialize[T]: AnyConstructor[T] = macro AnyConstructorMacro.mkAnyConstructor[T]
 }
 
 object ClassConstructor {
-  def apply[T: ClassConstructor]: ClassConstructor[T] = implicitly
+  def apply[T](implicit ctor: ClassConstructor[T]): ProviderMagnet[T] = ctor.provider
 
   implicit def materialize[T]: ClassConstructor[T] = macro ClassConstructorMacro.mkClassConstructor[T]
 }
 
 object TraitConstructor {
-  def apply[T: TraitConstructor]: TraitConstructor[T] = implicitly
+  def apply[T](implicit ctor: TraitConstructor[T]): ProviderMagnet[T] = ctor.provider
 
   implicit def materialize[T]: TraitConstructor[T] = macro TraitConstructorMacro.mkTraitConstructor[T]
 
@@ -43,28 +41,29 @@ object TraitConstructor {
 }
 
 object FactoryConstructor {
-  def apply[T: FactoryConstructor]: FactoryConstructor[T] = implicitly
+  def apply[T](implicit ctor: FactoryConstructor[T]): ProviderMagnet[T] = ctor.provider
 
   implicit def materialize[T]: FactoryConstructor[T] = macro FactoryConstructorMacro.mkFactoryConstructor[T]
 }
 
-private[constructors] sealed trait AnyConstructorOptionalMakeDSL[T] {
+private[constructors] sealed trait AnyConstructorOptionalMakeDSL[T] extends Any {
   def provider: ProviderMagnet[T]
 }
 object AnyConstructorOptionalMakeDSL {
-  def errorConstructor[T](tpe: String, nonWhitelistedMethods: List[String]): AnyConstructorOptionalMakeDSL[T] = {
-    new AnyConstructorOptionalMakeDSL[T] {
-      val provider: ProviderMagnet[T] = ProviderMagnet.lift(throwError(tpe, nonWhitelistedMethods, scaladoc = false))
-    }
+  private[constructors] final class Impl[T](val provider: ProviderMagnet[T]) extends AnyVal with AnyConstructorOptionalMakeDSL[T]
+
+  @inline def apply[T](providerMagnet: ProviderMagnet[T]): AnyConstructorOptionalMakeDSL.Impl[T] = {
+    new AnyConstructorOptionalMakeDSL.Impl[T](providerMagnet)
   }
 
-  def throwError(tpe: String, nonWhitelistedMethods: List[String], scaladoc: Boolean): Nothing = {
+  def errorConstructor[T](tpe: String, nonWhitelistedMethods: List[String]): AnyConstructorOptionalMakeDSL.Impl[T] = {
+    AnyConstructorOptionalMakeDSL[T](ProviderMagnet.lift(throwError(tpe, nonWhitelistedMethods)))
+  }
+
+  def throwError(tpe: String, nonWhitelistedMethods: List[String]): Nothing = {
     import izumi.fundamentals.platform.strings.IzString._
 
     throw new UnsupportedDefinitionException(
-      (if (scaladoc)
-        """This method was generated for ScalaDoc: if you're seeing this error,
-          |then AnyConstructorMacro mistook your compiler's behavior for running under Scaladoc, please report this as a bug!""".stripMargin else "") +
       s"""`make[$tpe]` DSL failure: Called an empty error constructor, because constructor for $tpe WAS NOT generated.
          |Because after `make` there were following method calls in the same expression:${nonWhitelistedMethods.niceList()}
          |
@@ -74,11 +73,5 @@ object AnyConstructorOptionalMakeDSL {
     )
   }
 
-  def apply[T](anyConstructor: AnyConstructor[T]): AnyConstructorOptionalMakeDSL[T] = {
-    new AnyConstructorOptionalMakeDSL[T] {
-      val provider: ProviderMagnet[T] = anyConstructor.provider
-    }
-  }
-
-  implicit def materialize[T]: AnyConstructorOptionalMakeDSL[T] = macro AnyConstructorMacro.anyConstructorOptionalMakeDSL[T]
+  implicit def materialize[T]: AnyConstructorOptionalMakeDSL.Impl[T] = macro AnyConstructorMacro.anyConstructorOptionalMakeDSL[T]
 }
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/AnyConstructorMacro.scala b/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/AnyConstructorMacro.scala
index bfec830d8..3dd8d1630 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/AnyConstructorMacro.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/AnyConstructorMacro.scala
@@ -15,10 +15,10 @@ object AnyConstructorMacro {
 
   def make[B[_], T: c.WeakTypeTag](c: blackbox.Context): c.Expr[B[T]] = {
     import c.universe._
-    c.Expr[B[T]](q"""${c.prefix}._make[${weakTypeOf[T]}]((${c.inferImplicitValue(weakTypeOf[AnyConstructorOptionalMakeDSL[T]], silent = false)}).provider)""")
+    c.Expr[B[T]](q"""${c.prefix}._make[${weakTypeOf[T]}](${c.inferImplicitValue(weakTypeOf[AnyConstructorOptionalMakeDSL[T]], silent = false)}.provider)""")
   }
 
-  def anyConstructorOptionalMakeDSL[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[AnyConstructorOptionalMakeDSL[T]] = {
+  def anyConstructorOptionalMakeDSL[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[AnyConstructorOptionalMakeDSL.Impl[T]] = {
     import c.universe._
 
     val logger = TrivialMacroLogger.make[this.type](c, DebugProperties.`izumi.debug.macro.distage.constructors`)
@@ -62,7 +62,7 @@ object AnyConstructorMacro {
 
     val tpe = weakTypeOf[T]
 
-    c.Expr[AnyConstructorOptionalMakeDSL[T]] {
+    c.Expr[AnyConstructorOptionalMakeDSL.Impl[T]] {
       maybeNonwhiteListedMethods match {
         case None =>
           c.abort(c.enclosingPosition,
@@ -77,7 +77,7 @@ object AnyConstructorMacro {
           if (nonwhiteListedMethods.isEmpty) {
             logger.log(s"""For $tpe found no `.from`-like calls in $maybeTree""".stripMargin)
 
-            q"""_root_.izumi.distage.constructors.AnyConstructorOptionalMakeDSL.apply[$tpe](${mkAnyConstructor[T](c)})"""
+            q"""_root_.izumi.distage.constructors.AnyConstructorOptionalMakeDSL.apply[$tpe](${mkAnyConstructor[T](c)}.provider)"""
           } else {
             logger.log(s"For $tpe found `.from`-like calls, generating ERROR constructor: $nonwhiteListedMethods")
 
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/ConstructorMacros.scala b/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/ConstructorMacros.scala
index 741345655..f5c9d9bfa 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/ConstructorMacros.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/ConstructorMacros.scala
@@ -1,9 +1,10 @@
 package izumi.distage.constructors.macros
 
 import izumi.distage.model.providers.ProviderMagnet
-import izumi.distage.model.reflection.ReflectionProvider
+import izumi.distage.model.reflection.Provider.ProviderType
 import izumi.distage.model.reflection.macros.DIUniverseLiftables
-import izumi.distage.model.reflection.universe.{RuntimeDIUniverse, StaticDIUniverse}
+import izumi.distage.model.reflection.universe.StaticDIUniverse
+import izumi.distage.model.reflection.{Provider, ReflectionProvider}
 import izumi.fundamentals.reflection.ReflectionUtil
 
 import scala.annotation.tailrec
@@ -14,7 +15,7 @@ abstract class ClassConstructorMacros extends ConstructorMacrosBase {
 
   def mkClassConstructorProvider[T: c.WeakTypeTag](reflectionProvider: ReflectionProvider.Aux[u.type])(targetType: Type): c.Expr[ProviderMagnet[T]] = {
     val associations = reflectionProvider.constructorParameterLists(targetType)
-    generateProvider[T](associations)(args => q"new $targetType(...$args)")
+    generateProvider[T, ProviderType.Class.type](associations)(args => q"new $targetType(...$args)")
   }
 }
 object ClassConstructorMacros {
@@ -34,7 +35,7 @@ abstract class TraitConstructorMacros extends ConstructorMacrosBase {
     val u.Wiring.SingletonWiring.Trait(targetType, classParameters, methods, _) = wiring
     val traitParameters = methods.map(_.asParameter)
 
-    generateProvider[T](classParameters :+ traitParameters) {
+    generateProvider[T, ProviderType.Trait.type](classParameters :+ traitParameters) {
       argss => q"_root_.izumi.distage.constructors.TraitConstructor.wrapInitialization[$targetType](${
         val methodDefs = methods.zip(argss.last).map {
           case (method, paramSeqIndexTree) => method.traitMethodExpr(paramSeqIndexTree)
@@ -243,8 +244,8 @@ abstract class ConstructorMacrosBase {
     }
   }
 
-  def generateProvider[T: c.WeakTypeTag](parameters: List[List[u.Association.Parameter]])
-                                        (fun: List[List[Tree]] => Tree): c.Expr[ProviderMagnet[T]] = {
+  def generateProvider[T: c.WeakTypeTag, P <: ProviderType with Singleton: c.WeakTypeTag](parameters: List[List[u.Association.Parameter]])
+                                                                                         (fun: List[List[Tree]] => Tree): c.Expr[ProviderMagnet[T]] = {
     val tools = DIUniverseLiftables(u)
     import tools.{liftTypeToSafeType, liftableParameter}
 
@@ -268,11 +269,11 @@ abstract class ConstructorMacrosBase {
     c.Expr[ProviderMagnet[T]] {
       q"""{
           new ${weakTypeOf[ProviderMagnet[T]]}(
-            new ${weakTypeOf[RuntimeDIUniverse.Provider.ProviderImpl[T]]}(
+            new ${weakTypeOf[Provider.ProviderImpl[T]]}(
               ${Liftable.liftList.apply(parameters.flatten)},
               ${liftTypeToSafeType(weakTypeOf[T])},
               { ($seqName: _root_.scala.Seq[_root_.scala.Any]) => ${fun(casts)}: ${weakTypeOf[T]} },
-              true,
+             ${symbolOf[P].asClass.module},
             )
           )
         }"""
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/FactoryConstructorMacro.scala b/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/FactoryConstructorMacro.scala
index 0161be296..dd33b663c 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/FactoryConstructorMacro.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/FactoryConstructorMacro.scala
@@ -2,6 +2,7 @@ package izumi.distage.constructors.macros
 
 import izumi.distage.constructors.{DebugProperties, FactoryConstructor}
 import izumi.distage.model.providers.ProviderMagnet
+import izumi.distage.model.reflection.Provider.ProviderType
 import izumi.distage.model.reflection.universe.StaticDIUniverse
 import izumi.distage.reflection.ReflectionProviderDefaultImpl
 import izumi.fundamentals.reflection.{ReflectionUtil, TrivialMacroLogger}
@@ -26,7 +27,7 @@ object FactoryConstructorMacro {
     val macroUniverse.Wiring.Factory.WithProductDeps(factoryMethods, classParameters, methods, factoryProductsDeps) = symbolToFactory(reflectionProvider)(targetType)
     val allParameters = classParameters :+ (methods ++ factoryProductsDeps).map(_.asParameter)
 
-    val provider: c.Expr[ProviderMagnet[T]] = generateProvider[T](allParameters) {
+    val provider: c.Expr[ProviderMagnet[T]] = generateProvider[T, ProviderType.Factory.type](allParameters) {
       argss =>
       val dependencyArgMap = allParameters.iterator.flatten.map(_.key).zip(argss.iterator.flatten).toMap
       logger.log(
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/Injector.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/Injector.scala
index 2498acc72..6e29d12dd 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/Injector.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/Injector.scala
@@ -5,7 +5,7 @@ import izumi.distage.model.definition.ModuleBase
 import izumi.distage.model.effect.DIEffect
 import izumi.distage.model.plan.GCMode
 import izumi.distage.model.providers.ProviderMagnet
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 import izumi.fundamentals.reflection.Tags.{Tag, TagK}
 import izumi.fundamentals.platform.functional.Identity
 
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/Locator.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/Locator.scala
index 7f23770a9..211630c00 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/Locator.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/Locator.scala
@@ -5,7 +5,7 @@ import izumi.distage.model.plan.OrderedPlan
 import izumi.distage.model.providers.ProviderMagnet
 import izumi.distage.model.provisioning.PlanInterpreter.Finalizer
 import izumi.distage.model.references.IdentifiedRef
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.{DIKey, TypedRef}
+import izumi.distage.model.reflection.{DIKey, TypedRef}
 import izumi.fundamentals.reflection.Tags.{Tag, TagK}
 
 import scala.collection.immutable
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/Planner.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/Planner.scala
index 4f0c33fdc..1ac70b5e0 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/Planner.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/Planner.scala
@@ -4,7 +4,7 @@ import izumi.distage.model.definition.ModuleBase
 import izumi.distage.model.plan._
 import izumi.distage.model.plan.initial.PrePlan
 import izumi.distage.model.planning.PlanSplittingOps
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 
 /** Transforms [[ModuleBase]] into [[OrderedPlan]] */
 trait Planner extends PlanSplittingOps {
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/PlannerInput.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/PlannerInput.scala
index 9818b4eb9..85aba4276 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/PlannerInput.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/PlannerInput.scala
@@ -2,7 +2,7 @@ package izumi.distage.model
 
 import izumi.distage.model.definition.ModuleBase
 import izumi.distage.model.plan.GCMode
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 import izumi.fundamentals.reflection.Tags.Tag
 
 /**
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/Binding.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/Binding.scala
index b1901a167..259b92470 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/Binding.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/Binding.scala
@@ -4,8 +4,7 @@ import izumi.distage.constructors.AnyConstructor
 import izumi.distage.model.definition.Binding.GroupingKey
 import izumi.distage.model.plan.repr.{BindingFormatter, KeyFormatter}
 import izumi.distage.model.providers.ProviderMagnet
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.fundamentals.platform.language.SourceFilePosition
 import izumi.fundamentals.reflection.Tags.Tag
 
@@ -58,7 +57,7 @@ object Binding {
   final case class SingletonBinding[+K <: DIKey](key: K, implementation: ImplDef, tags: Set[BindingTag], origin: SourceFilePosition) extends ImplBinding with WithTarget {
     override lazy val group: GroupingKey = GroupingKey.KeyImpl(key, implementation)
     override def withImplDef(implDef: ImplDef): SingletonBinding[K] = copy(implementation = implDef)
-    override def withTarget[T <: RuntimeDIUniverse.DIKey](key: T): SingletonBinding[T] = copy(key = key)
+    override def withTarget[T <: DIKey](key: T): SingletonBinding[T] = copy(key = key)
     protected[this] def withTags(newTags: Set[BindingTag]): SingletonBinding[K] = copy(tags = newTags)
     override def addTags(moreTags: Set[BindingTag]): SingletonBinding[K] = withTags(this.tags ++ moreTags)
   }
@@ -72,14 +71,14 @@ object Binding {
 
   final case class EmptySetBinding[+K <: DIKey](key: K, tags: Set[BindingTag], origin: SourceFilePosition) extends SetBinding with WithTarget {
     override lazy val group: GroupingKey = GroupingKey.Key(key)
-    override def withTarget[T <: RuntimeDIUniverse.DIKey](key: T): EmptySetBinding[T] = copy(key = key)
+    override def withTarget[T <: DIKey](key: T): EmptySetBinding[T] = copy(key = key)
     protected[this] def withTags(newTags: Set[BindingTag]): EmptySetBinding[K] = copy(tags = newTags)
     override def addTags(moreTags: Set[BindingTag]): EmptySetBinding[K] = withTags(this.tags ++ moreTags)
   }
 
   implicit final class WithImplementation[R](private val binding: ImplBinding {def withImplDef(implDef: ImplDef): R}) extends AnyVal {
     def withImpl[T: Tag: AnyConstructor]: R =
-      withImpl[T](AnyConstructor[T].provider)
+      withImpl[T](AnyConstructor[T])
 
     def withImpl[T: Tag](instance: T): R =
       binding.withImplDef(ImplDef.InstanceImpl(SafeType.get[T], instance))
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/Bindings.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/Bindings.scala
index 7853ae0c7..70afaf255 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/Bindings.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/Bindings.scala
@@ -3,16 +3,16 @@ package izumi.distage.model.definition
 import izumi.distage.constructors.AnyConstructor
 import izumi.distage.model.definition.Binding.{EmptySetBinding, SetElementBinding, SingletonBinding}
 import izumi.distage.model.providers.ProviderMagnet
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.{DIKey, SafeType}
+import izumi.distage.model.reflection.{DIKey, SafeType}
 import izumi.fundamentals.platform.language.CodePositionMaterializer
 import izumi.fundamentals.reflection.Tags.Tag
 
 object Bindings {
   def binding[T: Tag: AnyConstructor](implicit pos: CodePositionMaterializer): SingletonBinding[DIKey.TypeKey] =
-    provider[T](AnyConstructor[T].provider)
+    provider[T](AnyConstructor[T])
 
   def binding[T: Tag, I <: T: Tag: AnyConstructor](implicit pos: CodePositionMaterializer): SingletonBinding[DIKey.TypeKey] =
-    provider[T](AnyConstructor[I].provider)
+    provider[T](AnyConstructor[I])
 
   def binding[T: Tag, I <: T: Tag](instance: I)(implicit pos: CodePositionMaterializer): SingletonBinding[DIKey.TypeKey] =
     SingletonBinding(DIKey.get[T], ImplDef.InstanceImpl(SafeType.get[I], instance), Set.empty, pos.get.position)
@@ -30,7 +30,7 @@ object Bindings {
     EmptySetBinding(DIKey.get[Set[T]], Set.empty, pos.get.position)
 
   def setElement[T: Tag, I <: T: Tag: AnyConstructor](implicit pos: CodePositionMaterializer): SetElementBinding = {
-    setElementProvider[T](AnyConstructor[I].provider)
+    setElementProvider[T](AnyConstructor[I])
   }
 
   def setElement[T: Tag, I <: T: Tag](instance: I)(implicit pos: CodePositionMaterializer): SetElementBinding = {
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/DIResource.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/DIResource.scala
index 06a7eb704..671ac36fa 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/DIResource.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/DIResource.scala
@@ -484,12 +484,17 @@ object DIResource {
     final def evalTap[G[x] >: F[x]: DIEffect](f: OuterResource => G[Unit]): DIResourceBase[G, OuterResource] = evalMap[G, OuterResource](a => DIEffect[G].map(f(a))(_ => a))
 
     /** Wrap acquire action of this resource in another effect, e.g. for logging purposes */
-    final def logAcquire[G[x] >: F[x]](f: (=> G[InnerResource]) => G[InnerResource]): DIResourceBase[G, OuterResource] = logAcquireImpl[G, OuterResource](this: this.type)(f)
+    final def wrapAcquire[G[x] >: F[x]](f: (=> G[InnerResource]) => G[InnerResource]): DIResourceBase[G, OuterResource] = wrapAcquireImpl[G, OuterResource](this: this.type)(f)
 
     /** Wrap release action of this resource in another effect, e.g. for logging purposes */
-    final def logRelease[G[x] >: F[x]](f: (InnerResource => G[Unit], InnerResource) => G[Unit]): DIResourceBase[G, OuterResource] = logReleaseImpl[G, OuterResource](this: this.type)(f)
+    final def wrapRelease[G[x] >: F[x]](f: (InnerResource => G[Unit], InnerResource) => G[Unit]): DIResourceBase[G, OuterResource] = wrapReleaseImpl[G, OuterResource](this: this.type)(f)
 
     final def void: DIResourceBase[F, Unit] = map(_ => ())
+
+    @deprecated("Use wrapAcquire", "will be removed in 0.10.3")
+    final def logAcquire[G[x] >: F[x]](f: (=> G[InnerResource]) => G[InnerResource]): DIResourceBase[G, OuterResource] = wrapAcquire(f)
+    @deprecated("Use wrapRelease", "will be removed in 0.10.3")
+    final def logRelease[G[x] >: F[x]](f: (InnerResource => G[Unit], InnerResource) => G[Unit]): DIResourceBase[G, OuterResource] = wrapRelease(f)
   }
 
   object DIResourceBase {
@@ -633,6 +638,10 @@ object DIResource {
 
     new DIResourceBase[F, B] {
       override type InnerResource = InnerResource0
+      sealed trait InnerResource0 {
+        def extract: B
+        def deallocate: F[Unit]
+      }
       override def acquire: F[InnerResource] = {
         bracketOnError(self.acquire)(self.release) {
           inner1 =>
@@ -652,11 +661,6 @@ object DIResource {
       }
       override def release(resource: InnerResource): F[Unit] = resource.deallocate
       override def extract(resource: InnerResource): B = resource.extract
-
-      sealed trait InnerResource0 {
-        def extract: B
-        def deallocate: F[Unit]
-      }
     }
   }
 
@@ -666,7 +670,7 @@ object DIResource {
   }
 
   @inline
-  private[this] final def logAcquireImpl[F[_], A](self: DIResourceBase[F, A])(f: (=> F[self.InnerResource]) => F[self.InnerResource]): DIResourceBase[F, A] = {
+  private[this] final def wrapAcquireImpl[F[_], A](self: DIResourceBase[F, A])(f: (=> F[self.InnerResource]) => F[self.InnerResource]): DIResourceBase[F, A] = {
     new DIResourceBase[F, A] {
       override final type InnerResource = self.InnerResource
       override def acquire: F[InnerResource] = f(self.acquire)
@@ -676,7 +680,7 @@ object DIResource {
   }
 
   @inline
-  private[this] final def logReleaseImpl[F[_], A](self: DIResourceBase[F, A])(f: (self.InnerResource => F[Unit], self.InnerResource) => F[Unit]): DIResourceBase[F, A] = {
+  private[this] final def wrapReleaseImpl[F[_], A](self: DIResourceBase[F, A])(f: (self.InnerResource => F[Unit], self.InnerResource) => F[Unit]): DIResourceBase[F, A] = {
     new DIResourceBase[F, A] {
       override final type InnerResource = self.InnerResource
       override def acquire: F[InnerResource] = self.acquire
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/ImplDef.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/ImplDef.scala
index 9e546f8d4..233fed34b 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/ImplDef.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/ImplDef.scala
@@ -1,7 +1,7 @@
 package izumi.distage.model.definition
 
 import izumi.distage.model.plan.repr.{BindingFormatter, KeyFormatter}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.{DIKey, Provider, SafeType}
+import izumi.distage.model.reflection.{DIKey, Provider, SafeType}
 
 sealed trait ImplDef {
   def implType: SafeType
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/LocatorDef.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/LocatorDef.scala
index 6945348ac..866e083d6 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/LocatorDef.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/LocatorDef.scala
@@ -9,6 +9,7 @@ import izumi.distage.model.definition.dsl.AbstractBindingDefDSL.SingletonInstruc
 import izumi.distage.model.definition.dsl.AbstractBindingDefDSL._
 import izumi.distage.model.exceptions.LocatorDefUninstantiatedBindingException
 import izumi.distage.model.plan.ExecutableOp.WiringOp.UseInstance
+import izumi.distage.model.plan.Wiring.SingletonWiring.Instance
 import izumi.distage.model.plan._
 import izumi.distage.model.plan.operations.OperationOrigin
 import izumi.distage.model.plan.topology.DependencyGraph
@@ -16,8 +17,7 @@ import izumi.distage.model.plan.topology.DependencyGraph.DependencyKind
 import izumi.distage.model.plan.topology.PlanTopology.PlanTopologyImmutable
 import izumi.distage.model.provisioning.PlanInterpreter
 import izumi.distage.model.references.IdentifiedRef
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.Wiring.SingletonWiring.Instance
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.distage.model.{Locator, definition}
 import izumi.fundamentals.platform.language.{CodePositionMaterializer, SourceFilePosition}
 import izumi.fundamentals.reflection.Tags.{Tag, TagK}
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/ModuleBase.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/ModuleBase.scala
index ca83a6ea1..534460335 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/ModuleBase.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/ModuleBase.scala
@@ -3,7 +3,7 @@ package izumi.distage.model.definition
 import cats.Hash
 import cats.kernel.{BoundedSemilattice, PartialOrder}
 import izumi.distage.model.definition.ModuleBaseInstances.{CatsBoundedSemilattice, CatsPartialOrderHash, ModuleBaseSemilattice}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 import izumi.fundamentals.collections.IzCollections._
 import izumi.fundamentals.platform.language.unused
 
@@ -180,7 +180,7 @@ object ModuleBase {
     *
     * Optional instance via https://blog.7mind.io/no-more-orphans.html
     */
-  implicit def optionalCatsPartialOrderHashForModuleBase[T <: ModuleBase, K[_] : CatsPartialOrderHash]: K[T] = {
+  implicit def optionalCatsPartialOrderHashForModuleBase[T <: ModuleBase, K[_]: CatsPartialOrderHash]: K[T] = {
     import cats.instances.set._
 
     new PartialOrder[T] with Hash[T] {
@@ -196,14 +196,14 @@ object ModuleBase {
     *
     * Optional instance via https://blog.7mind.io/no-more-orphans.html
     */
-  implicit def optionalCatsSemilatticeForModuleBase[T <: ModuleBase.Aux[T] : ModuleMake, K[_] : CatsBoundedSemilattice]: K[T] =
+  implicit def optionalCatsSemilatticeForModuleBase[T <: ModuleBase.Aux[T]: ModuleMake, K[_]: CatsBoundedSemilattice]: K[T] =
     new ModuleBaseSemilattice[T].asInstanceOf[K[T]]
 
 }
 
 private object ModuleBaseInstances {
 
-  final class ModuleBaseSemilattice[T <: ModuleBase.Aux[T] : ModuleMake] extends BoundedSemilattice[T] {
+  final class ModuleBaseSemilattice[T <: ModuleBase.Aux[T]: ModuleMake] extends BoundedSemilattice[T] {
     def empty: T = ModuleMake[T].empty
     def combine(x: T, y: T): T = x ++ y
   }
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/dsl/AbstractBindingDefDSL.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/dsl/AbstractBindingDefDSL.scala
index 8c356dddb..c4caba1d4 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/dsl/AbstractBindingDefDSL.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/dsl/AbstractBindingDefDSL.scala
@@ -8,7 +8,7 @@ import izumi.distage.model.definition.dsl.AbstractBindingDefDSL.SingletonInstruc
 import izumi.distage.model.definition.dsl.AbstractBindingDefDSL._
 import izumi.distage.model.definition.{Binding, BindingTag, Bindings, ImplDef}
 import izumi.distage.model.providers.ProviderMagnet
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.{DIKey, IdContract}
+import izumi.distage.model.reflection.{DIKey, IdContract}
 import izumi.fundamentals.platform.language.Quirks._
 import izumi.fundamentals.platform.language.{CodePositionMaterializer, SourceFilePosition}
 import izumi.fundamentals.reflection.Tags.Tag
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/dsl/ModuleDefDSL.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/dsl/ModuleDefDSL.scala
index 9bf59c53d..24a94dc01 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/dsl/ModuleDefDSL.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/dsl/ModuleDefDSL.scala
@@ -10,7 +10,7 @@ import izumi.distage.model.definition.dsl.AbstractBindingDefDSL.SingletonInstruc
 import izumi.distage.model.definition.dsl.AbstractBindingDefDSL.{SetInstruction, SingletonInstruction, _}
 import izumi.distage.model.definition.dsl.ModuleDefDSL.{MakeDSL, SetDSL}
 import izumi.distage.model.providers.ProviderMagnet
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection.{DIKey, IdContract, SafeType}
 import izumi.fundamentals.platform.language.CodePositionMaterializer
 import izumi.fundamentals.platform.language.Quirks.discard
 import izumi.fundamentals.reflection.Tags.{Tag, TagK}
@@ -97,7 +97,7 @@ object ModuleDefDSL {
 
   trait MakeDSLBase[T, AfterBind] {
     final def from[I <: T: AnyConstructor]: AfterBind =
-      from(AnyConstructor[I].provider)
+      from(AnyConstructor[I])
 
     final def from[I <: T: Tag](function: => I): AfterBind =
       from(ProviderMagnet.lift(function))
@@ -119,6 +119,7 @@ object ModuleDefDSL {
       * }}}
       *
       * Method reference:
+      *
       * {{{
       *   def constructor(@Id("special") i: Int): Unit = ()
       *
@@ -127,14 +128,14 @@ object ModuleDefDSL {
       *   make[Unit].from(constructor(_))
       * }}}
       *
-      * Function value (possibly with annotated signature):
+      * Function value with an annotated signature:
+      *
       * {{{
       *   val constructor: (Int @Id("special"), String @Id("special")) => Unit = (_, _) => ()
       *
       *   make[Unit].from(constructor)
       * }}}
       *
-      *
       * Annotation processing is done by a macro and macros are rarely perfect,
       * Prefer passing an inline lambda such as { x => y } or a method reference such as (method _) or (method(_))
       * Annotation info may be lost ONLY in a few cases detailed below, though:
@@ -173,6 +174,7 @@ object ModuleDefDSL {
       * }}}
       *
       * @see [[izumi.distage.model.reflection.macros.ProviderMagnetMacro]]
+      * @see 'Magnet' in the name refers to the Magnet Pattern: http://spray.io/blog/2012-12-13-the-magnet-pattern/
       */
     final def from[I <: T](function: ProviderMagnet[I]): AfterBind =
       bind(ImplDef.ProviderImpl(function.get.ret, function.get))
@@ -273,7 +275,7 @@ object ModuleDefDSL {
       *      - [[DIResource]]
       */
     final def fromResource[R <: DIResourceBase[Any, T]: AnyConstructor](implicit tag: ResourceTag[R]): AfterBind = {
-      fromResource[R](AnyConstructor[R].provider)
+      fromResource[R](AnyConstructor[R])
     }
 
     final def fromResource[R](instance: R with DIResourceBase[Any, T])(implicit tag: ResourceTag[R]): AfterBind = {
@@ -318,7 +320,7 @@ object ModuleDefDSL {
   trait SetDSLBase[T, AfterAdd, AfterMultiAdd] {
 
     final def add[I <: T: Tag: AnyConstructor](implicit pos: CodePositionMaterializer): AfterAdd =
-      add[I](AnyConstructor[I].provider)
+      add[I](AnyConstructor[I])
 
     final def add[I <: T: Tag](function: => I)(implicit pos: CodePositionMaterializer): AfterAdd =
       add(ProviderMagnet.lift(function))
@@ -401,7 +403,7 @@ object ModuleDefDSL {
       appendElement(ImplDef.EffectImpl(SafeType.get[I], SafeType.getK[F], ImplDef.ReferenceImpl(SafeType.get[F[I]], DIKey.get[F[I]].named(name), weak = false)), pos)
 
     final def addResource[R <: DIResourceBase[Any, T]: AnyConstructor](implicit tag: ResourceTag[R], pos: CodePositionMaterializer): AfterAdd =
-      addResource[R](AnyConstructor[R].provider)
+      addResource[R](AnyConstructor[R])
 
     final def addResource[R](instance: R with DIResourceBase[Any, T])(implicit tag: ResourceTag[R], pos: CodePositionMaterializer): AfterAdd = {
       import tag._
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/ConflictingDIKeyBindingsException.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/ConflictingDIKeyBindingsException.scala
index 9c36b91b8..38d5707cf 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/ConflictingDIKeyBindingsException.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/ConflictingDIKeyBindingsException.scala
@@ -1,6 +1,6 @@
 package izumi.distage.model.exceptions
 
 import izumi.distage.model.planning.PlanMergingPolicy.DIKeyConflictResolution
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.DIKey
 
-class ConflictingDIKeyBindingsException(message: String, val conflicts: Map[RuntimeDIUniverse.DIKey, DIKeyConflictResolution.Failed]) extends DIException(message)
+class ConflictingDIKeyBindingsException(message: String, val conflicts: Map[DIKey, DIKeyConflictResolution.Failed]) extends DIException(message)
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/DuplicateInstancesException.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/DuplicateInstancesException.scala
index b023edda6..16debab43 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/DuplicateInstancesException.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/DuplicateInstancesException.scala
@@ -1,8 +1,8 @@
 package izumi.distage.model.exceptions
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.DIKey
 
-case class DuplicateInstancesException(key: RuntimeDIUniverse.DIKey) extends DIException(
+case class DuplicateInstancesException(key: DIKey) extends DIException(
   s"Cannot continue, key is already in the object graph: $key"
 )
 
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/DuplicateKeysException.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/DuplicateKeysException.scala
index 0896573c6..efab9abcd 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/DuplicateKeysException.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/DuplicateKeysException.scala
@@ -1,8 +1,8 @@
 package izumi.distage.model.exceptions
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.DIKey
 
-class DuplicateKeysException(message: String, val keys: Map[RuntimeDIUniverse.DIKey, Int]) extends DIException(message)
+class DuplicateKeysException(message: String, val keys: Map[DIKey, Int]) extends DIException(message)
 
 
 
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/IncompatibleEffectTypesException.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/IncompatibleEffectTypesException.scala
index 02505b51c..3216ae6ba 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/IncompatibleEffectTypesException.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/IncompatibleEffectTypesException.scala
@@ -1,6 +1,6 @@
 package izumi.distage.model.exceptions
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.SafeType
+import izumi.distage.model.reflection.SafeType
 
 class IncompatibleEffectTypesException(val provisionerEffectType: SafeType, val actionEffectType: SafeType) extends DIException(
   s"""Incompatible effect types: Can't execute effect in `$actionEffectType` which is neither Identity, nor a subtype of the effect that Provisioner was launched in: `$provisionerEffectType`
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/IncompatibleRuntimeClassException.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/IncompatibleRuntimeClassException.scala
index 4955a4ad0..e7afd241d 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/IncompatibleRuntimeClassException.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/IncompatibleRuntimeClassException.scala
@@ -1,9 +1,9 @@
 package izumi.distage.model.exceptions
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.DIKey
 
 class IncompatibleRuntimeClassException(
-                                         val expected: RuntimeDIUniverse.DIKey,
+                                         val expected: DIKey,
                                          val got: Class[_],
                                          val clue: String,
                                        ) extends DIException(
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/IncompatibleTypesException.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/IncompatibleTypesException.scala
index 425779120..ea9b57a4b 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/IncompatibleTypesException.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/IncompatibleTypesException.scala
@@ -1,11 +1,11 @@
 package izumi.distage.model.exceptions
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.SafeType
 
 class IncompatibleTypesException(
-                                  message: String
-                                  , val expected: RuntimeDIUniverse.SafeType
-                                  , val got: RuntimeDIUniverse.SafeType
+                                  message: String,
+                                  val expected: SafeType,
+                                  val got: SafeType,
                                 ) extends DIException(message)
 
 
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/MissingInstanceException.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/MissingInstanceException.scala
index 29b4bcf09..29b81939a 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/MissingInstanceException.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/MissingInstanceException.scala
@@ -1,6 +1,6 @@
 package izumi.distage.model.exceptions
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 import izumi.fundamentals.platform.strings.IzString._
 
 class MissingInstanceException(message: String, val key: DIKey) extends DIException(message)
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/MissingProxyAdapterException.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/MissingProxyAdapterException.scala
index ae1157fd1..965f9d4d1 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/MissingProxyAdapterException.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/MissingProxyAdapterException.scala
@@ -1,6 +1,6 @@
 package izumi.distage.model.exceptions
 
 import izumi.distage.model.plan.ExecutableOp.ProxyOp
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.DIKey
 
-class MissingProxyAdapterException(message: String, val key: RuntimeDIUniverse.DIKey, val op: ProxyOp) extends DIException(message)
+class MissingProxyAdapterException(message: String, val key: DIKey, val op: ProxyOp) extends DIException(message)
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/MissingRefException.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/MissingRefException.scala
index 905a11b8a..7edd04726 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/MissingRefException.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/MissingRefException.scala
@@ -1,6 +1,6 @@
 package izumi.distage.model.exceptions
 
 import izumi.distage.model.plan.topology.PlanTopology
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.DIKey
 
-class MissingRefException(message: String, val missing: Set[RuntimeDIUniverse.DIKey], val topology: Option[PlanTopology]) extends DIException(message)
+class MissingRefException(message: String, val missing: Set[DIKey], val topology: Option[PlanTopology]) extends DIException(message)
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/MissingRootsException.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/MissingRootsException.scala
index 19e48d800..ce68dd226 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/MissingRootsException.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/MissingRootsException.scala
@@ -1,5 +1,5 @@
 package izumi.distage.model.exceptions
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.DIKey
 
-class MissingRootsException(message: String, val roots: Set[RuntimeDIUniverse.DIKey]) extends DIException(message)
+class MissingRootsException(message: String, val roots: Set[DIKey]) extends DIException(message)
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/ModuleMergeException.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/ModuleMergeException.scala
index 81a75461b..a050cf41b 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/ModuleMergeException.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/ModuleMergeException.scala
@@ -1,5 +1,5 @@
 package izumi.distage.model.exceptions
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.DIKey
 
-class ModuleMergeException(message: String, val badKeys: Set[RuntimeDIUniverse.DIKey]) extends DIException(message)
+class ModuleMergeException(message: String, val badKeys: Set[DIKey]) extends DIException(message)
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/NoRuntimeClassException.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/NoRuntimeClassException.scala
index ceda4ef41..f272ba27d 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/NoRuntimeClassException.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/NoRuntimeClassException.scala
@@ -1,12 +1,12 @@
 package izumi.distage.model.exceptions
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.{DIKey, SafeType}
 
 class NoRuntimeClassException(
-                               val operation: RuntimeDIUniverse.DIKey,
-                               val key: RuntimeDIUniverse.SafeType,
+                               val operation: DIKey,
+                               val key: SafeType,
                              ) extends DIException(
   s"Cannot build proxy for operation $operation: runtime class is not available for $key"
 ) {
-  def this(operation: RuntimeDIUniverse.DIKey) = this(operation, operation.tpe)
+  def this(operation: DIKey) = this(operation, operation.tpe)
 }
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/TODOBindingException.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/TODOBindingException.scala
index f40922795..449fb8d2e 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/TODOBindingException.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/TODOBindingException.scala
@@ -1,6 +1,6 @@
 package izumi.distage.model.exceptions
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.DIKey
 import izumi.fundamentals.platform.language.CodePositionMaterializer
 
-class TODOBindingException(message: String, val target: RuntimeDIUniverse.DIKey, val sourcePosition: CodePositionMaterializer) extends DIException(message)
+class TODOBindingException(message: String, val target: DIKey, val sourcePosition: CodePositionMaterializer) extends DIException(message)
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/TraitInitializationFailedException.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/TraitInitializationFailedException.scala
index e870613dc..61c062a96 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/TraitInitializationFailedException.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/TraitInitializationFailedException.scala
@@ -1,5 +1,5 @@
 package izumi.distage.model.exceptions
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.SafeType
 
-class TraitInitializationFailedException(message: String, val tpe: RuntimeDIUniverse.SafeType, cause: Throwable) extends DIException(message, cause)
+class TraitInitializationFailedException(message: String, val tpe: SafeType, cause: Throwable) extends DIException(message, cause)
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/UnsafeCallArgsMismatched.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/UnsafeCallArgsMismatched.scala
index c65dcd586..f9f23c385 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/UnsafeCallArgsMismatched.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/exceptions/UnsafeCallArgsMismatched.scala
@@ -1,6 +1,6 @@
 package izumi.distage.model.exceptions
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.SafeType
+import izumi.distage.model.reflection.SafeType
 
 class UnsafeCallArgsMismatched(message: String, val expected: Seq[SafeType], val actual: Seq[SafeType], val actualValues: Seq[Any]) extends DIException(message)
 
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/AbstractPlan.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/AbstractPlan.scala
index 41b1c2379..a0b96177b 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/AbstractPlan.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/AbstractPlan.scala
@@ -4,7 +4,7 @@ import izumi.distage.model.definition.ModuleBase
 import izumi.distage.model.plan.ExecutableOp.SemiplanOp
 import izumi.distage.model.plan.impl.{OrderedPlanExtensions, OrderedPlanOps, PlanLazyOps, SemiPlanExtensions, SemiPlanOps}
 import izumi.distage.model.plan.topology.PlanTopology
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 
 sealed trait AbstractPlan[OpType <: ExecutableOp] extends AbstractPlanExtendedAPI[OpType] with PlanLazyOps[OpType] {
   def definition: ModuleBase
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/AbstractPlanExtendedAPI.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/AbstractPlanExtendedAPI.scala
index 7fe6051f2..004cc0900 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/AbstractPlanExtendedAPI.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/AbstractPlanExtendedAPI.scala
@@ -2,7 +2,7 @@ package izumi.distage.model.plan
 
 import izumi.distage.model.Locator
 import izumi.distage.model.plan.ExecutableOp.{ImportDependency, SemiplanOp}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.fundamentals.reflection.Tags.Tag
 
 private[plan] trait AbstractPlanExtendedAPI[OpType <: ExecutableOp] extends Any {
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/ExecutableOp.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/ExecutableOp.scala
index 30f1fa245..613c4ac16 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/ExecutableOp.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/ExecutableOp.scala
@@ -1,10 +1,10 @@
 package izumi.distage.model.plan
 
 import izumi.distage.model.plan.ExecutableOp.ProxyOp.{InitProxy, MakeProxy}
+import izumi.distage.model.plan.Wiring.SingletonWiring
 import izumi.distage.model.plan.operations.OperationOrigin
 import izumi.distage.model.plan.repr.{KeyFormatter, OpFormatter, TypeFormatter}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.Wiring._
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection.{DIKey, SafeType}
 
 import scala.annotation.tailrec
 
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/GCMode.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/GCMode.scala
index 9f831ce19..a13c4e64a 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/GCMode.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/GCMode.scala
@@ -1,6 +1,6 @@
 package izumi.distage.model.plan
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.fundamentals.reflection.Tags.Tag
 
 sealed trait GCMode {
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/Wiring.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/Wiring.scala
new file mode 100644
index 000000000..75c2ef61f
--- /dev/null
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/Wiring.scala
@@ -0,0 +1,58 @@
+package izumi.distage.model.plan
+
+import izumi.distage.model.reflection.{Association, DIKey, Provider, SafeType}
+import izumi.fundamentals.platform.language.unused
+
+sealed trait Wiring {
+  def instanceType: SafeType
+  def associations: Seq[Association]
+  def replaceKeys(f: Association => DIKey.BasicKey): Wiring
+
+  def requiredKeys: Set[DIKey] = associations.map(_.key).toSet
+}
+
+object Wiring {
+  sealed trait SingletonWiring extends Wiring {
+    def instanceType: SafeType
+    override def replaceKeys(f: Association => DIKey.BasicKey): SingletonWiring
+  }
+  object SingletonWiring {
+    final case class Function(provider: Provider, associations: Seq[Association.Parameter]) extends SingletonWiring {
+      override final def instanceType: SafeType = provider.ret
+
+      override final def replaceKeys(f: Association => DIKey.BasicKey): Function = this.copy(associations = this.associations.map(a => a.withKey(f(a))))
+    }
+    final case class Instance(instanceType: SafeType, instance: Any) extends SingletonWiring {
+      override final def associations: Seq[Association] = Seq.empty
+
+      override final def replaceKeys(@unused f: Association => DIKey.BasicKey): Instance = this
+    }
+    final case class Reference(instanceType: SafeType, key: DIKey, weak: Boolean) extends SingletonWiring {
+      override final def associations: Seq[Association] = Seq.empty
+
+      override final val requiredKeys: Set[DIKey] = super.requiredKeys ++ Set(key)
+      override final def replaceKeys(@unused f: Association => DIKey.BasicKey): Reference = this
+    }
+  }
+
+  sealed trait MonadicWiring extends Wiring {
+    def effectWiring: SingletonWiring
+    def effectHKTypeCtor: SafeType
+  }
+  object MonadicWiring {
+    final case class Effect(instanceType: SafeType, effectHKTypeCtor: SafeType, effectWiring: SingletonWiring) extends MonadicWiring {
+      override final def associations: Seq[Association] = effectWiring.associations
+      override final def requiredKeys: Set[DIKey] = effectWiring.requiredKeys
+
+      override final def replaceKeys(f: Association => DIKey.BasicKey): Effect = copy(effectWiring = effectWiring.replaceKeys(f))
+    }
+
+    final case class Resource(instanceType: SafeType, effectHKTypeCtor: SafeType, effectWiring: SingletonWiring) extends MonadicWiring {
+      override final def associations: Seq[Association] = effectWiring.associations
+      override final def requiredKeys: Set[DIKey] = effectWiring.requiredKeys
+
+      override final def replaceKeys(f: Association => DIKey.BasicKey): Resource = copy(effectWiring = effectWiring.replaceKeys(f))
+    }
+  }
+
+}
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/AbstractPlanOps.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/AbstractPlanOps.scala
index bb0aabc4b..37c721a0f 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/AbstractPlanOps.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/AbstractPlanOps.scala
@@ -3,7 +3,7 @@ package izumi.distage.model.plan.impl
 import izumi.distage.model.plan.ExecutableOp
 import izumi.distage.model.plan.ExecutableOp.WiringOp.UseInstance
 import izumi.distage.model.plan.ExecutableOp.{ImportDependency, SemiplanOp}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.Wiring.SingletonWiring.Instance
+import izumi.distage.model.plan.Wiring.SingletonWiring.Instance
 
 private[plan] object AbstractPlanOps {
   def resolveImports[OpType <: ExecutableOp](f: PartialFunction[ImportDependency, Seq[OpType]], steps: Vector[OpType]): Vector[ExecutableOp] =
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/OrderedPlanOps.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/OrderedPlanOps.scala
index 18ce0a600..8ac9cb7fe 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/OrderedPlanOps.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/OrderedPlanOps.scala
@@ -5,7 +5,7 @@ import izumi.distage.model.exceptions.{InvalidPlanException, MissingInstanceExce
 import izumi.distage.model.plan.ExecutableOp.ProxyOp.{InitProxy, MakeProxy}
 import izumi.distage.model.plan.ExecutableOp.{ImportDependency, ProxyOp, SemiplanOp}
 import izumi.distage.model.plan.{GCMode, OrderedPlan, SemiPlan}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.distage.model.recursive.LocatorRef
 import izumi.fundamentals.reflection.Tags.Tag
 
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/PlanCatsSyntaxImpl.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/PlanCatsSyntaxImpl.scala
index fa3875da5..b546388fc 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/PlanCatsSyntaxImpl.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/PlanCatsSyntaxImpl.scala
@@ -4,22 +4,22 @@ import cats.Applicative
 import cats.kernel.Monoid
 import izumi.distage.model.plan.ExecutableOp.WiringOp.UseInstance
 import izumi.distage.model.plan.ExecutableOp.{ImportDependency, SemiplanOp}
+import izumi.distage.model.plan.Wiring.SingletonWiring.Instance
 import izumi.distage.model.plan.{ExecutableOp, OrderedPlan, SemiPlan}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.Wiring.SingletonWiring.Instance
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.fundamentals.reflection.Tags.Tag
 
 private[plan] object PlanCatsSyntaxImpl {
 
   final class ResolveImportFSemiPlanPartiallyApplied[T](private val plan: SemiPlan) extends AnyVal {
-    def apply[F[_] : Applicative](f: F[T])(implicit ev: Tag[T]): F[SemiPlan] =
+    def apply[F[_]: Applicative](f: F[T])(implicit ev: Tag[T]): F[SemiPlan] =
       plan.resolveImportsF[F] {
         case i if i.target == DIKey.get[T] => f.asInstanceOf[F[Any]]
       }
   }
 
   final class ResolveImportFOrderedPlanPartiallyApplied[T](private val plan: OrderedPlan) extends AnyVal {
-    def apply[F[_] : Applicative](f: F[T])(implicit ev: Tag[T]): F[OrderedPlan] =
+    def apply[F[_]: Applicative](f: F[T])(implicit ev: Tag[T]): F[OrderedPlan] =
       plan.resolveImportsF[F] {
         case i if i.target == DIKey.get[T] => f.asInstanceOf[F[Any]]
       }
@@ -41,7 +41,7 @@ private[plan] object PlanCatsSyntaxImpl {
   import cats.syntax.traverse._
 
   @inline
-  final def resolveImportsImpl[F[_] : Applicative](f: PartialFunction[ImportDependency, F[Any]], steps: Vector[ExecutableOp]): F[Vector[ExecutableOp]] =
+  final def resolveImportsImpl[F[_]: Applicative](f: PartialFunction[ImportDependency, F[Any]], steps: Vector[ExecutableOp]): F[Vector[ExecutableOp]] =
     steps.traverse {
       case i: ImportDependency =>
         f.lift(i).map {
@@ -52,7 +52,7 @@ private[plan] object PlanCatsSyntaxImpl {
     }
 
   @inline
-  final def resolveImportsImpl1[F[_] : Applicative](f: PartialFunction[ImportDependency, F[Any]], steps: Vector[SemiplanOp]): F[Vector[SemiplanOp]] =
+  final def resolveImportsImpl1[F[_]: Applicative](f: PartialFunction[ImportDependency, F[Any]], steps: Vector[SemiplanOp]): F[Vector[SemiplanOp]] =
     steps.traverse {
       case i: ImportDependency =>
         f.lift(i).map {
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/PlanLazyOps.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/PlanLazyOps.scala
index 554789dfd..b1f08080f 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/PlanLazyOps.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/PlanLazyOps.scala
@@ -3,7 +3,7 @@ package izumi.distage.model.plan.impl
 import izumi.distage.model.definition.ModuleBase
 import izumi.distage.model.plan.operations.OperationOrigin
 import izumi.distage.model.plan.{AbstractPlan, ExecutableOp}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 
 private[plan] trait PlanLazyOps[OpType <: ExecutableOp] {
   this: AbstractPlan[OpType] =>
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/SemiPlanOps.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/SemiPlanOps.scala
index 3ae316faf..81cead93a 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/SemiPlanOps.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/impl/SemiPlanOps.scala
@@ -4,9 +4,9 @@ import izumi.distage.model.Locator
 import izumi.distage.model.plan.ExecutableOp.WiringOp.CallProvider
 import izumi.distage.model.plan.ExecutableOp.{ImportDependency, SemiplanOp}
 import izumi.distage.model.plan.SemiPlan
+import izumi.distage.model.plan.Wiring.SingletonWiring
 import izumi.distage.model.providers.ProviderMagnet
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.Wiring.SingletonWiring
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.fundamentals.reflection.Tags.Tag
 
 private[plan] trait SemiPlanOps extends Any {
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/initial/NextOps.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/initial/NextOps.scala
index 792416717..8de787de6 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/initial/NextOps.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/initial/NextOps.scala
@@ -1,9 +1,9 @@
 package izumi.distage.model.plan.initial
 
 import izumi.distage.model.plan.ExecutableOp.{CreateSet, InstantiationOp}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.DIKey
 
 final case class NextOps(
-                          sets: Map[RuntimeDIUniverse.DIKey, CreateSet],
+                          sets: Map[DIKey, CreateSet],
                           provisions: Seq[InstantiationOp],
                         )
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/initial/PrePlan.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/initial/PrePlan.scala
index bcd60ebaa..8037db416 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/initial/PrePlan.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/initial/PrePlan.scala
@@ -4,7 +4,7 @@ import izumi.distage.model.definition.{Binding, ModuleBase}
 import izumi.distage.model.plan.ExecutableOp.{CreateSet, InstantiationOp}
 import izumi.distage.model.plan.GCMode
 import izumi.distage.model.plan.initial.PrePlan.{JustOp, SetOp, TraceableOp}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 import izumi.fundamentals.collections.ImmutableMultiMap
 import izumi.fundamentals.platform.language.Quirks
 import izumi.fundamentals.platform.language.Quirks._
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/BindingFormatter.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/BindingFormatter.scala
index 927078746..92746b74e 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/BindingFormatter.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/BindingFormatter.scala
@@ -1,7 +1,7 @@
 package izumi.distage.model.plan.repr
 
 import izumi.distage.model.definition.{Binding, BindingTag, ImplDef}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey.SetElementKey
+import izumi.distage.model.reflection.DIKey.SetElementKey
 
 trait BindingFormatter {
   def formatBinding(binding: Binding): String
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/DepTreeRenderer.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/DepTreeRenderer.scala
index d6ab62dd9..4856aa9db 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/DepTreeRenderer.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/DepTreeRenderer.scala
@@ -5,7 +5,7 @@ import izumi.distage.model.plan.topology.DepTreeNode._
 import izumi.distage.model.plan.topology.DependencyGraph.DependencyKind
 import izumi.distage.model.plan.OrderedPlan
 import izumi.distage.model.plan.operations.OperationOrigin
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 
 import scala.collection.mutable
 
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/KeyFormatter.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/KeyFormatter.scala
index 5315a9f77..67e6605e1 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/KeyFormatter.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/KeyFormatter.scala
@@ -1,6 +1,6 @@
 package izumi.distage.model.plan.repr
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.{DIKey, SafeType}
+import izumi.distage.model.reflection.{DIKey, SafeType}
 
 trait KeyFormatter {
   def formatKey(key: DIKey): String
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/KeyMinimizer.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/KeyMinimizer.scala
index 94c46093c..183a00421 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/KeyMinimizer.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/KeyMinimizer.scala
@@ -1,6 +1,6 @@
 package izumi.distage.model.plan.repr
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.fundamentals.collections.IzCollections._
 import izumi.fundamentals.reflection.macrortti.LightTypeTagRef.SymName
 import izumi.fundamentals.reflection.macrortti.{LTTRenderables, LightTypeTagRef, RuntimeAPI}
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/OpFormatter.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/OpFormatter.scala
index d31a632a6..ad53f0d68 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/OpFormatter.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/OpFormatter.scala
@@ -1,14 +1,14 @@
 package izumi.distage.model.plan.repr
 
-import izumi.distage.model.plan.ExecutableOp
 import izumi.distage.model.plan.ExecutableOp.MonadicOp._
 import izumi.distage.model.plan.ExecutableOp.ProxyOp._
 import izumi.distage.model.plan.ExecutableOp.WiringOp._
 import izumi.distage.model.plan.ExecutableOp.{CreateSet, ImportDependency, InstantiationOp, WiringOp, _}
+import izumi.distage.model.plan.Wiring.MonadicWiring._
+import izumi.distage.model.plan.Wiring.SingletonWiring._
 import izumi.distage.model.plan.operations.OperationOrigin
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.Wiring.MonadicWiring._
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.Wiring.SingletonWiring._
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.{Association, DIKey, Provider, Wiring}
+import izumi.distage.model.plan.{ExecutableOp, Wiring}
+import izumi.distage.model.reflection.{Association, DIKey, Provider}
 import izumi.fundamentals.platform.strings.IzString._
 
 trait OpFormatter {
@@ -134,7 +134,7 @@ object OpFormatter {
     }
 
     private def formatFunction(provider: Provider): String = {
-      s"${provider.fun}(${provider.argTypes.map(formatType).mkString(", ")}): ${formatType(provider.ret)}"
+      s"${provider.funString}(${provider.argTypes.map(formatType).mkString(", ")}): ${formatType(provider.ret)}"
     }
 
     //    private def formatPrefix(prefix: Option[DIKey]): Seq[String] = {
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/topology/DepTreeNode.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/topology/DepTreeNode.scala
index 37796ad45..972d298a3 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/topology/DepTreeNode.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/topology/DepTreeNode.scala
@@ -1,5 +1,5 @@
 package izumi.distage.model.plan.topology
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 
 sealed trait DepTreeNode {
   def level: Int
@@ -29,4 +29,4 @@ object DepTreeNode {
     }
   }
 
-}
\ No newline at end of file
+}
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/topology/DependencyGraph.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/topology/DependencyGraph.scala
index 6fa64bb13..af1be1c0c 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/topology/DependencyGraph.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/topology/DependencyGraph.scala
@@ -2,7 +2,7 @@ package izumi.distage.model.plan.topology
 
 import izumi.distage.model.plan.topology.DepTreeNode.DepNode
 import izumi.distage.model.plan.topology.DependencyGraph.DependencyKind
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 
 import scala.collection.mutable
 
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/topology/PlanTopology.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/topology/PlanTopology.scala
index f775306bf..1ec6037c9 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/topology/PlanTopology.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/topology/PlanTopology.scala
@@ -1,7 +1,7 @@
 package izumi.distage.model.plan.topology
 
 import izumi.distage.model.plan.topology.DependencyGraph.DependencyKind
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 
 
 /**
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/planning/PlanAnalyzer.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/planning/PlanAnalyzer.scala
index f716eefbd..8ded8c4d7 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/planning/PlanAnalyzer.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/planning/PlanAnalyzer.scala
@@ -2,7 +2,7 @@ package izumi.distage.model.planning
 
 import izumi.distage.model.plan.ExecutableOp
 import izumi.distage.model.plan.topology.PlanTopology
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 
 trait PlanAnalyzer {
   def topology(ops: Seq[ExecutableOp]): PlanTopology
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/planning/PlanMergingPolicy.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/planning/PlanMergingPolicy.scala
index 382699159..6f07f7ae4 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/planning/PlanMergingPolicy.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/planning/PlanMergingPolicy.scala
@@ -4,7 +4,7 @@ import izumi.distage.model.plan.initial.PrePlan.{JustOp, SetOp, TraceableOp}
 import izumi.distage.model.plan.ExecutableOp.SemiplanOp
 import izumi.distage.model.plan.SemiPlan
 import izumi.distage.model.plan.initial.PrePlan
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 
 trait PlanMergingPolicy {
   def freeze(plan: PrePlan): SemiPlan
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/planning/PlanSplittingOps.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/planning/PlanSplittingOps.scala
index e24230638..86319a80b 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/planning/PlanSplittingOps.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/planning/PlanSplittingOps.scala
@@ -2,7 +2,7 @@ package izumi.distage.model.planning
 
 import izumi.distage.model.definition.ModuleBase
 import izumi.distage.model.plan.{OrderedPlan, TriSplittedPlan}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.distage.model.{Planner, PlannerInput}
 
 trait PlanSplittingOps {
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/planning/PlanningHook.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/planning/PlanningHook.scala
index 0ee0fa169..b49565ffc 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/planning/PlanningHook.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/planning/PlanningHook.scala
@@ -3,7 +3,7 @@ package izumi.distage.model.planning
 import izumi.distage.model.definition.{Binding, ModuleBase}
 import izumi.distage.model.plan.initial.PrePlan
 import izumi.distage.model.plan.{OrderedPlan, SemiPlan}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.Wiring
+import izumi.distage.model.plan.Wiring
 import izumi.fundamentals.platform.language.Quirks._
 
 trait PlanningHook {
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/providers/ProviderMagnet.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/providers/ProviderMagnet.scala
index ce0ec2b33..915f38a95 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/providers/ProviderMagnet.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/providers/ProviderMagnet.scala
@@ -2,8 +2,9 @@ package izumi.distage.model.providers
 
 import izumi.distage.model.exceptions.TODOBindingException
 import izumi.distage.model.reflection.macros.ProviderMagnetMacro
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.Association.Parameter
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection.Association.Parameter
+import izumi.distage.model.reflection.Provider.ProviderType
+import izumi.distage.model.reflection._
 import izumi.fundamentals.platform.language.{CodePositionMaterializer, unused}
 import izumi.fundamentals.platform.language.Quirks._
 import izumi.fundamentals.reflection.Tags.Tag
@@ -34,7 +35,7 @@ import scala.language.implicitConversions
   *   make[Unit].from(constructor(_))
   * }}}
   *
-  * Function value with annotated signature:
+  * Function value with an annotated signature:
   *
   * {{{
   *   val constructor: (Int @Id("special"), String @Id("special")) => Unit = (_, _) => ()
@@ -42,7 +43,6 @@ import scala.language.implicitConversions
   *   make[Unit].from(constructor)
   * }}}
   *
-  *
   * Annotation processing is done by a macro and macros are rarely perfect,
   * Prefer passing an inline lambda such as { x => y } or a method reference such as (method _) or (method(_))
   * Annotation info may be lost ONLY in a few cases detailed below, though:
@@ -83,6 +83,7 @@ import scala.language.implicitConversions
   * ProviderMagnet forms an applicative functor via its [[ProviderMagnet.pure]] & [[map2]] methods
   *
   * @see [[izumi.distage.model.reflection.macros.ProviderMagnetMacro]]]
+  * @see 'Magnet' in the name refers to the Magnet Pattern: http://spray.io/blog/2012-12-13-the-magnet-pattern/
   */
 final case class ProviderMagnet[+A](get: Provider) {
   def map[B: Tag](f: A => B): ProviderMagnet[B] = {
@@ -152,7 +153,7 @@ object ProviderMagnet {
         parameters = Seq.empty,
         ret = key.tpe,
         fun = _ => throw new TODOBindingException(s"Tried to instantiate a 'TODO' binding for $key defined at ${pos.get}!", key, pos),
-        isGenerated = false,
+        providerType = ProviderType.Function,
       )
     )
 
@@ -167,9 +168,18 @@ object ProviderMagnet {
         ret = SafeType.get[A],
         originalFun = () => a,
         fun = (_: Seq[Any]) => a,
-        isGenerated = false,
-      )
-    )
+        providerType = ProviderType.Function,
+      ))
+  }
+
+  def singleton[A <: Singleton: Tag](a: A): ProviderMagnet[A] = {
+    new ProviderMagnet[A](
+      Provider.ProviderImpl[A](
+        parameters = Seq.empty,
+        ret = SafeType.get[A],
+        fun = (_: Seq[Any]) => a,
+        providerType = ProviderType.Singleton,
+      ))
   }
 
   def single[A: Tag, B: Tag](f: A => B): ProviderMagnet[B] = {
@@ -184,18 +194,7 @@ object ProviderMagnet {
         ret = retTpe,
         originalFun = f,
         fun = (s: Seq[Any]) => f(s.head.asInstanceOf[A]),
-        isGenerated = false,
-      )
-    )
-  }
-
-  def singleton[A <: Singleton: Tag](a: A): ProviderMagnet[A] = {
-    new ProviderMagnet[A](
-      Provider.ProviderImpl[A](
-        parameters = Seq.empty,
-        ret = SafeType.get[A],
-        fun = (_: Seq[Any]) => a,
-        isGenerated = true,
+        providerType = ProviderType.Function,
       )
     )
   }
@@ -209,7 +208,7 @@ object ProviderMagnet {
         parameters = Seq(Parameter(symbolInfo, key)),
         ret = tpe,
         fun = (_: Seq[Any]).head,
-        isGenerated = false,
+        providerType = ProviderType.Function,
       )
     )
   }
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/NewObjectOp.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/NewObjectOp.scala
index 780ae23f2..0daa192df 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/NewObjectOp.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/NewObjectOp.scala
@@ -1,6 +1,6 @@
 package izumi.distage.model.provisioning
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 
 sealed trait NewObjectOp
 object NewObjectOp {
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/PlanInterpreter.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/PlanInterpreter.scala
index c1910eb2d..2764a3edf 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/PlanInterpreter.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/PlanInterpreter.scala
@@ -8,7 +8,7 @@ import izumi.distage.model.plan.OrderedPlan
 import izumi.distage.model.plan.repr.OpFormatter
 import izumi.distage.model.provisioning.PlanInterpreter.{FailedProvision, FinalizerFilter}
 import izumi.distage.model.provisioning.Provision.ProvisionImmutable
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.fundamentals.reflection.Tags.TagK
 
 trait PlanInterpreter {
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/Provision.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/Provision.scala
index 4caf107ba..c78a41fbd 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/Provision.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/Provision.scala
@@ -2,7 +2,7 @@ package izumi.distage.model.provisioning
 
 import izumi.distage.model.provisioning.PlanInterpreter.Finalizer
 import izumi.distage.model.references.IdentifiedRef
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 
 import scala.collection.{Map, Seq, mutable}
 
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/ProvisioningKeyProvider.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/ProvisioningKeyProvider.scala
index 2245d539e..d4d9ac9fa 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/ProvisioningKeyProvider.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/ProvisioningKeyProvider.scala
@@ -1,6 +1,6 @@
 package izumi.distage.model.provisioning
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 
 trait ProvisioningKeyProvider {
   /** Return the object referred by `key` if available
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/proxies/ProxyDispatcher.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/proxies/ProxyDispatcher.scala
index bce6e575c..26154cb8e 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/proxies/ProxyDispatcher.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/proxies/ProxyDispatcher.scala
@@ -3,7 +3,7 @@ package izumi.distage.model.provisioning.proxies
 import java.util.concurrent.atomic.AtomicReference
 
 import izumi.distage.model.exceptions.{MissingRefException, ProxyAlreadyInitializedException}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 
 trait ProxyDispatcher {
   def init(real: Any): Unit
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/proxies/ProxyProvider.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/proxies/ProxyProvider.scala
index 32b5461a5..0abb1bfd4 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/proxies/ProxyProvider.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/proxies/ProxyProvider.scala
@@ -3,7 +3,7 @@ package izumi.distage.model.provisioning.proxies
 import izumi.distage.model.exceptions.NoopProvisionerImplCalled
 import izumi.distage.model.plan.ExecutableOp
 import izumi.distage.model.provisioning.proxies.ProxyProvider.{DeferredInit, ProxyContext}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 
 trait ProxyProvider {
   def makeCycleProxy(deferredKey: DIKey, proxyContext: ProxyContext): DeferredInit
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/references/IdentifiedRef.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/references/IdentifiedRef.scala
index 6c8eb931f..b7a3a0706 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/references/IdentifiedRef.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/references/IdentifiedRef.scala
@@ -1,5 +1,5 @@
 package izumi.distage.model.references
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 
 final case class IdentifiedRef(key: DIKey, value: Any)
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/Association.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/Association.scala
new file mode 100644
index 000000000..b5652bb9a
--- /dev/null
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/Association.scala
@@ -0,0 +1,20 @@
+package izumi.distage.model.reflection
+
+sealed trait Association {
+  def symbol: SymbolInfo
+  def key: DIKey
+  def name: String
+  def isByName: Boolean
+
+  def withKey(key: DIKey): Association
+}
+
+object Association {
+  final case class Parameter(symbol: SymbolInfo, key: DIKey) extends Association {
+    override final def name: String = symbol.name
+    override final def isByName: Boolean = symbol.isByName
+    override final def withKey(key: DIKey): Association.Parameter = copy(key = key)
+
+    final def wasGeneric: Boolean = symbol.wasGeneric
+  }
+}
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/DIKey.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/DIKey.scala
new file mode 100644
index 000000000..adcb0c0a8
--- /dev/null
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/DIKey.scala
@@ -0,0 +1,60 @@
+package izumi.distage.model.reflection
+
+import izumi.distage.model.definition.ImplDef
+import izumi.fundamentals.reflection.Tags.Tag
+
+sealed trait DIKey {
+  def tpe: SafeType
+  override lazy val hashCode: Int = scala.util.hashing.MurmurHash3.productHash(this.asInstanceOf[Product])
+}
+
+object DIKey {
+  def get[T: Tag]: DIKey.TypeKey = TypeKey(SafeType.get[T])
+
+  sealed trait BasicKey extends DIKey {
+    def withTpe(tpe: SafeType): DIKey.BasicKey
+  }
+
+  final case class TypeKey(tpe: SafeType) extends BasicKey {
+    final def named[I: IdContract](id: I): IdKey[I] = IdKey(tpe, id)
+
+    override final def withTpe(tpe: SafeType): DIKey.TypeKey = copy(tpe = tpe)
+    override final def toString: String = s"{type.${tpe.toString}}"
+  }
+
+  final case class IdKey[I: IdContract](tpe: SafeType, id: I) extends BasicKey {
+    final val idContract: IdContract[I] = implicitly
+
+    override final def withTpe(tpe: SafeType): DIKey.IdKey[I] = copy(tpe = tpe)
+    override final def toString: String = s"{type.${tpe.toString}@${idContract.repr(id)}}"
+  }
+
+  final case class ProxyElementKey(proxied: DIKey, tpe: SafeType) extends DIKey {
+    override final def toString: String = s"{proxy.${proxied.toString}}"
+  }
+
+  final case class ResourceKey(key: DIKey, tpe: SafeType) extends DIKey {
+    override final def toString: String = s"{resource.${key.toString}/$tpe}"
+  }
+
+  final case class EffectKey(key: DIKey, tpe: SafeType) extends DIKey {
+    override final def toString: String = s"{effect.${key.toString}/$tpe}"
+  }
+
+  /**
+    * @param set       Key of the parent Set. `set.tpe` must be of type `Set[T]`
+    * @param reference Key of `this` individual element. `reference.tpe` must be a subtype of `T`
+    */
+  final case class SetElementKey(set: DIKey, reference: DIKey, disambiguator: Option[ImplDef]) extends DIKey {
+    override final def tpe: SafeType = reference.tpe
+
+    override final def toString: String = s"{set.$set/${reference.toString}#${disambiguator.fold("0")(_.hashCode.toString)}"
+  }
+
+  final case class MultiSetImplId(set: DIKey, impl: ImplDef)
+  object MultiSetImplId {
+    implicit object SetImplIdContract extends IdContract[MultiSetImplId] {
+      override def repr(v: MultiSetImplId): String = s"set/${v.set}#${v.impl.hashCode}"
+    }
+  }
+}
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/IdContract.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/IdContract.scala
new file mode 100644
index 000000000..c36bbfc9f
--- /dev/null
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/IdContract.scala
@@ -0,0 +1,17 @@
+package izumi.distage.model.reflection
+
+trait IdContract[T] {
+  def repr(v: T): String
+}
+object IdContract {
+  implicit val stringIdContract: IdContract[String] = new IdContractImpl[String]
+  implicit def singletonStringIdContract[S <: String with Singleton]: IdContract[S] = new IdContractImpl[S]
+
+  final class IdContractImpl[T] extends IdContract[T] {
+    override def repr(value: T): String = value.toString
+  }
+}
+
+
+
+
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/Provider.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/Provider.scala
new file mode 100644
index 000000000..a9f0033b7
--- /dev/null
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/Provider.scala
@@ -0,0 +1,127 @@
+package izumi.distage.model.reflection
+
+import izumi.distage.model.exceptions.UnsafeCallArgsMismatched
+import izumi.distage.model.reflection.Provider.ProviderType
+
+trait Provider {
+  def parameters: Seq[Association.Parameter]
+  final def diKeys: Seq[DIKey] = parameters.map(_.key)
+  final def argTypes: Seq[SafeType] = parameters.map(_.key.tpe)
+  final def arity: Int = parameters.size
+  def ret: SafeType
+  def originalFun: AnyRef
+  def fun: Seq[Any] => Any
+  def providerType: ProviderType
+
+  def unsafeApply(refs: Seq[TypedRef[_]]): Any = {
+    val args = verifyArgs(refs)
+    fun(args)
+  }
+
+  def unsafeMap(newRet: SafeType, f: Any => _): Provider
+  def unsafeZip(newRet: SafeType, that: Provider): Provider
+  def addUnused(keys: Seq[DIKey]): Provider
+
+  private val eqField: AnyRef = {
+    if (providerType eq ProviderType.Function) originalFun
+    else if (providerType eq ProviderType.FunctionWithUnusedKeys) (originalFun, diKeys)
+    else ret
+  }
+  override final def equals(obj: Any): Boolean = obj match {
+    case that: Provider => eqField == that.eqField
+    case _              => false
+  }
+  override final def hashCode(): Int = eqField.hashCode()
+  override final def toString: String = s"$funString(${argTypes.mkString(", ")}): $ret"
+  final def funString = if (providerType eq ProviderType.Function) fun.toString else providerType.toString
+
+  protected[this] def verifyArgs(refs: Seq[TypedRef[_]]): Seq[Any] = {
+    val (newArgs, types, typesCmp) = parameters.zip(refs).map {
+      case (param, TypedRef(v, tpe, isByName)) =>
+
+        val newArg = if (param.isByName && !isByName) {
+          () => v
+        } else if (isByName && !param.isByName) {
+          v.asInstanceOf[Function0[Any]].apply()
+        } else v
+
+        (newArg, tpe, tpe <:< param.key.tpe)
+    }.unzip3
+
+    val countOk = refs.size == parameters.size
+    val typesOk = !typesCmp.contains(false)
+
+    if (countOk && typesOk) {
+      newArgs
+    } else {
+      throw new UnsafeCallArgsMismatched(
+        message =
+          s"""Mismatched arguments for unsafe call:
+             | ${if (!typesOk) "Wrong types!" else ""}
+             | ${if (!countOk) s"Expected number of arguments $arity, but got ${refs.size}" else ""}
+             |Expected types [${argTypes.mkString(",")}], got types [${types.mkString(",")}], values: (${newArgs.mkString(",")})""".stripMargin,
+        expected = argTypes,
+        actual = types,
+        actualValues = newArgs,
+      )
+    }
+  }
+}
+
+object Provider {
+
+  sealed trait ProviderType
+  object ProviderType {
+    case object Class extends ProviderType
+    case object Trait extends ProviderType
+    case object Factory extends ProviderType
+    case object Singleton extends ProviderType
+    case object Function extends ProviderType
+    case object FunctionWithUnusedKeys extends ProviderType
+  }
+
+  final case class ProviderImpl[+A](
+                                     parameters: Seq[Association.Parameter],
+                                     ret: SafeType,
+                                     originalFun: AnyRef,
+                                     fun: Seq[Any] => Any,
+                                     providerType: ProviderType,
+                                   ) extends Provider {
+    def this(parameters: Seq[Association.Parameter], ret: SafeType, fun: Seq[Any] => Any, providerType: ProviderType) =
+      this(parameters, ret, fun, fun, providerType)
+
+    override def unsafeApply(refs: Seq[TypedRef[_]]): A =
+      super.unsafeApply(refs).asInstanceOf[A]
+
+    override def unsafeMap(newRet: SafeType, f: Any => _): ProviderImpl[_] =
+      copy(
+        ret = newRet,
+        originalFun = f,
+        fun = xs => f.apply(fun(xs)),
+        providerType = ProviderType.Function,
+      )
+
+    override def addUnused(keys: Seq[DIKey]): Provider =
+      copy(
+        parameters = parameters ++ keys.map(key => Association.Parameter(SymbolInfo("<unused>", key.tpe, isByName = false, wasGeneric = false), key)),
+        providerType = ProviderType.FunctionWithUnusedKeys,
+      )
+
+    override def unsafeZip(newRet: SafeType, that: Provider): Provider = {
+      new ProviderImpl(
+        parameters = parameters ++ that.parameters,
+        ret = newRet,
+        fun = { args0 =>
+          val (args1, args2) = args0.splitAt(arity)
+          fun(args1) -> that.fun(args2)
+        },
+        providerType = ProviderType.Function,
+      )
+    }
+  }
+  object ProviderImpl {
+    @inline def apply[A](parameters: Seq[Association.Parameter], ret: SafeType, fun: Seq[Any] => Any, providerType: ProviderType): ProviderImpl[A] =
+      new ProviderImpl(parameters, ret, fun, providerType)
+  }
+
+}
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/SafeType.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/SafeType.scala
new file mode 100644
index 000000000..fe4a39d6c
--- /dev/null
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/SafeType.scala
@@ -0,0 +1,44 @@
+package izumi.distage.model.reflection
+
+import izumi.fundamentals.platform.functional.Identity
+import izumi.fundamentals.reflection.Tags.{Tag, TagK, WeakTag}
+import izumi.fundamentals.reflection.macrortti.LightTypeTag
+
+final case class SafeType private(
+                                   tag: LightTypeTag,
+                                   /*private[distage] val */ cls: Class[_],
+                                 ) {
+  override final lazy val hashCode: Int = tag.hashCode()
+  override final def toString: String = tag.repr
+
+  override final def equals(obj: Any): Boolean = {
+    obj match {
+      case that: SafeType =>
+        tag =:= that.tag
+      case _ =>
+        false
+    }
+  }
+
+  final def =:=(that: SafeType): Boolean = {
+    tag =:= that.tag
+  }
+
+  final def <:<(that: SafeType): Boolean = {
+    tag <:< that.tag
+  }
+
+  final def hasPreciseClass: Boolean = {
+    try tag.shortName == cls.getSimpleName catch {
+      case i: InternalError if i.getMessage == "Malformed class name" => false
+    }
+  }
+}
+
+object SafeType {
+  def get[T: Tag]: SafeType = SafeType(Tag[T].tag, Tag[T].closestClass)
+  def getK[K[_]: TagK]: SafeType = SafeType(TagK[K].tag, TagK[K].closestClass)
+  def unsafeGetWeak[T](implicit weakTag: WeakTag[T]): SafeType = SafeType(weakTag.tag, weakTag.closestClass)
+
+  lazy val identityEffectType: SafeType = SafeType.getK[Identity]
+}
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/SymbolInfo.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/SymbolInfo.scala
new file mode 100644
index 000000000..0dbdfa08c
--- /dev/null
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/SymbolInfo.scala
@@ -0,0 +1,10 @@
+package izumi.distage.model.reflection
+
+final case class SymbolInfo(
+                             name: String,
+                             finalResultType: SafeType,
+                             // no custom annotation support since 0.10.0... please comment on github issue https://github.com/7mind/izumi/issues/906 if desired!
+                             // annotations: List[u.Annotation]
+                             isByName: Boolean,
+                             wasGeneric: Boolean,
+                           )
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/TypedRef.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/TypedRef.scala
new file mode 100644
index 000000000..12e8b68bd
--- /dev/null
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/TypedRef.scala
@@ -0,0 +1,15 @@
+package izumi.distage.model.reflection
+
+import izumi.distage.model.provisioning.proxies.ProxyDispatcher.ByNameDispatcher
+import izumi.fundamentals.reflection.Tags.Tag
+
+final case class TypedRef[+T](private val v: T, tpe: SafeType, isByName: Boolean) {
+  def value: T = v match {
+    case d: ByNameDispatcher => d.apply().asInstanceOf[T]
+    case o => o
+  }
+}
+object TypedRef {
+  def apply[T: Tag](value: T): TypedRef[T] = TypedRef(value, SafeType.get[T], isByName = false)
+  def byName[T: Tag](value: => T): TypedRef[T] = TypedRef((() => value).asInstanceOf[T], SafeType.get[T], isByName = true)
+}
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/macros/DIUniverseLiftables.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/macros/DIUniverseLiftables.scala
index e3267f9b7..3f1c25d66 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/macros/DIUniverseLiftables.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/macros/DIUniverseLiftables.scala
@@ -7,24 +7,24 @@ class DIUniverseLiftables[D <: StaticDIUniverse](val u: D) {
   import u._
   import u.u._
 
-  protected[this] val runtimeDIUniverse: Tree = q"_root_.izumi.distage.model.reflection.universe.RuntimeDIUniverse"
+  protected[this] val modelReflectionPkg: Tree = q"_root_.izumi.distage.model.reflection"
 
   def liftTypeToSafeType(tpe: TypeNative): Tree = {
-    q"{ $runtimeDIUniverse.SafeType.get[${Liftable.liftType(tpe)}] }"
+    q"{ $modelReflectionPkg.SafeType.get[${Liftable.liftType(tpe)}] }"
   }
 
   // DIKey
 
   protected[this] implicit val liftableTypeKey: Liftable[DIKey.TypeKey] = {
     case DIKey.TypeKey(tpe) => q"""
-    { new $runtimeDIUniverse.DIKey.TypeKey(${liftTypeToSafeType(tpe.typeNative)}) }
+    { new $modelReflectionPkg.DIKey.TypeKey(${liftTypeToSafeType(tpe.typeNative)}) }
       """
   }
 
   protected[this] implicit val liftableIdKey: Liftable[DIKey.IdKey[_]] = {
     case idKey: DIKey.IdKey[_] =>
       val lifted = idKey.idContract.liftable(idKey.id)
-      q"""{ new $runtimeDIUniverse.DIKey.IdKey(${liftTypeToSafeType(idKey.tpe.typeNative)}, $lifted) }"""
+      q"""{ new $modelReflectionPkg.DIKey.IdKey(${liftTypeToSafeType(idKey.tpe.typeNative)}, $lifted) }"""
   }
 
   protected[this] implicit val liftableBasicDIKey: Liftable[DIKey.BasicKey] = {
@@ -43,7 +43,7 @@ class DIUniverseLiftables[D <: StaticDIUniverse](val u: D) {
   // (annotations always empty currently)
   protected[this] implicit val liftableSymbolInfo: Liftable[SymbolInfo] = {
     info =>
-      q"""{ $runtimeDIUniverse.SymbolInfo(
+      q"""{ $modelReflectionPkg.SymbolInfo(
       name = ${info.name},
       finalResultType = ${liftTypeToSafeType(info.nonByNameFinalResultType)},
       isByName = ${info.isByName},
@@ -55,7 +55,7 @@ class DIUniverseLiftables[D <: StaticDIUniverse](val u: D) {
 
   implicit val liftableParameter: Liftable[Association.Parameter] = {
     case Association.Parameter(symbol, key) =>
-      q"new $runtimeDIUniverse.Association.Parameter($symbol, $key)"
+      q"new $modelReflectionPkg.Association.Parameter($symbol, $key)"
   }
 
 }
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/macros/ProviderMagnetMacro.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/macros/ProviderMagnetMacro.scala
index 0bc731e54..1a7aac5a9 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/macros/ProviderMagnetMacro.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/macros/ProviderMagnetMacro.scala
@@ -2,8 +2,10 @@ package izumi.distage.model.reflection.macros
 
 import izumi.distage.constructors.DebugProperties
 import izumi.distage.model.providers.ProviderMagnet
+import izumi.distage.model.reflection.Provider
+import izumi.distage.model.reflection.Provider.ProviderType
+import izumi.distage.model.reflection.universe.StaticDIUniverse
 import izumi.distage.model.reflection.universe.StaticDIUniverse.Aux
-import izumi.distage.model.reflection.universe.{RuntimeDIUniverse, StaticDIUniverse}
 import izumi.distage.reflection.ReflectionProviderDefaultImpl
 import izumi.fundamentals.reflection.{AnnotationTools, TrivialMacroLogger}
 
@@ -34,7 +36,7 @@ class ProviderMagnetMacro0[C <: blackbox.Context](val c: C) {
 
   def impl[R: c.WeakTypeTag](fun: Tree): c.Expr[ProviderMagnet[R]] = {
     val associations = analyze(fun, weakTypeOf[R])
-    val result = generateProvider[R](associations, fun, false)
+    val result = generateProvider[R](associations, fun)
 
     logger.log(
       s"""DIKeyWrappedFunction info:
@@ -69,10 +71,7 @@ class ProviderMagnetMacro0[C <: blackbox.Context](val c: C) {
       )
   }
 
-  def generateProvider[R: c.WeakTypeTag](parameters: List[Association.Parameter],
-                                         fun: Tree,
-                                         isGenerated: Boolean,
-                                        ): c.Expr[ProviderMagnet[R]] = {
+  def generateProvider[R: c.WeakTypeTag](parameters: List[Association.Parameter], fun: Tree): c.Expr[ProviderMagnet[R]] = {
     val tools = DIUniverseLiftables(macroUniverse)
     import tools.{liftTypeToSafeType, liftableParameter}
 
@@ -84,12 +83,12 @@ class ProviderMagnetMacro0[C <: blackbox.Context](val c: C) {
         val fun = $fun
 
         new ${weakTypeOf[ProviderMagnet[R]]}(
-          new ${weakTypeOf[RuntimeDIUniverse.Provider.ProviderImpl[R]]}(
+          new ${weakTypeOf[Provider.ProviderImpl[R]]}(
             $parametersNoByName,
             ${liftTypeToSafeType(weakTypeOf[R])},
             fun,
             { seqAny => fun.asInstanceOf[(..${casts.map(_ => definitions.AnyTpe)}) => ${definitions.AnyTpe}](..$casts) },
-            $isGenerated,
+            ${symbolOf[ProviderType.Function.type].asClass.module},
           )
         )
       }"""
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/universe/RuntimeDIUniverse/RuntimeDIUniverse.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/universe/RuntimeDIUniverse/RuntimeDIUniverse.scala
deleted file mode 100644
index c699f90e4..000000000
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/universe/RuntimeDIUniverse/RuntimeDIUniverse.scala
+++ /dev/null
@@ -1,325 +0,0 @@
-package izumi.distage.model.reflection.universe.RuntimeDIUniverse
-
-import izumi.distage.model.definition.ImplDef
-import izumi.distage.model.exceptions.UnsafeCallArgsMismatched
-import izumi.distage.model.provisioning.proxies.ProxyDispatcher.ByNameDispatcher
-import izumi.fundamentals.platform.language.unused
-import izumi.fundamentals.reflection.Tags.{Tag, TagK, WeakTag}
-import izumi.fundamentals.reflection.macrortti.LightTypeTag
-
-final class IdContractImpl[T] extends IdContract[T] {
-  override def repr(value: T): String = value.toString
-}
-
-sealed trait Association {
-  def symbol: SymbolInfo
-  def key: DIKey
-  def name: String
-  def isByName: Boolean
-
-  def withKey(key: DIKey): Association
-}
-
-object Association {
-  final case class Parameter(symbol: SymbolInfo, key: DIKey) extends Association {
-    override final def name: String = symbol.name
-    override final def isByName: Boolean = symbol.isByName
-    override final def withKey(key: DIKey): Association.Parameter = copy(key = key)
-
-    final def wasGeneric: Boolean = symbol.wasGeneric
-  }
-}
-
-final case class SymbolInfo(
-                             name: String,
-                             finalResultType: SafeType,
-                             // no custom annotation support since 0.10.0... please comment on github issue https://github.com/7mind/izumi/issues/906 if desired!
-                             // annotations: List[u.Annotation]
-                             isByName: Boolean,
-                             wasGeneric: Boolean,
-                           )
-
-final case class SafeType private(
-                                   tag: LightTypeTag,
-                                   /*private[distage] val */ cls: Class[_],
-                                 ) {
-  override final lazy val hashCode: Int = tag.hashCode()
-  override final def toString: String = tag.repr
-
-  override final def equals(obj: Any): Boolean = {
-    obj match {
-      case that: SafeType =>
-        tag =:= that.tag
-      case _ =>
-        false
-    }
-  }
-
-  final def =:=(that: SafeType): Boolean = {
-    tag =:= that.tag
-  }
-
-  final def <:<(that: SafeType): Boolean = {
-    tag <:< that.tag
-  }
-
-  final def hasPreciseClass: Boolean = {
-    try tag.shortName == cls.getSimpleName catch {
-      case i: InternalError if i.getMessage == "Malformed class name" => false
-    }
-  }
-}
-
-object SafeType {
-  def get[T: Tag]: SafeType = SafeType(Tag[T].tag, Tag[T].closestClass)
-  def getK[K[_]: TagK]: SafeType = SafeType(TagK[K].tag, TagK[K].closestClass)
-  def unsafeGetWeak[T](implicit weakTag: WeakTag[T]): SafeType = SafeType(weakTag.tag, weakTag.closestClass)
-}
-
-// dikey
-
-sealed trait DIKey {
-  def tpe: SafeType
-  override lazy val hashCode: Int = scala.util.hashing.MurmurHash3.productHash(this.asInstanceOf[Product])
-}
-
-object DIKey {
-  def get[T: Tag]: DIKey.TypeKey = TypeKey(SafeType.get[T])
-
-  sealed trait BasicKey extends DIKey {
-    def withTpe(tpe: SafeType): DIKey.BasicKey
-  }
-
-  final case class TypeKey(tpe: SafeType) extends BasicKey {
-    final def named[I: IdContract](id: I): IdKey[I] = IdKey(tpe, id)
-
-    override final def withTpe(tpe: SafeType): DIKey.TypeKey = copy(tpe = tpe)
-    override final def toString: String = s"{type.${tpe.toString}}"
-  }
-
-  final case class IdKey[I: IdContract](tpe: SafeType, id: I) extends BasicKey {
-    final val idContract: IdContract[I] = implicitly
-
-    override final def withTpe(tpe: SafeType): DIKey.IdKey[I] = copy(tpe = tpe)
-    override final def toString: String = s"{type.${tpe.toString}@${idContract.repr(id)}}"
-  }
-
-  final case class ProxyElementKey(proxied: DIKey, tpe: SafeType) extends DIKey {
-    override final def toString: String = s"{proxy.${proxied.toString}}"
-  }
-
-  final case class ResourceKey(key: DIKey, tpe: SafeType) extends DIKey {
-    override final def toString: String = s"{resource.${key.toString}/$tpe}"
-  }
-
-  final case class EffectKey(key: DIKey, tpe: SafeType) extends DIKey {
-    override final def toString: String = s"{effect.${key.toString}/$tpe}"
-  }
-
-  /**
-    * @param set       Key of the parent Set. `set.tpe` must be of type `Set[T]`
-    * @param reference Key of `this` individual element. `reference.tpe` must be a subtype of `T`
-    */
-  final case class SetElementKey(set: DIKey, reference: DIKey, disambiguator: Option[ImplDef]) extends DIKey {
-    override final def tpe: SafeType = reference.tpe
-
-    override final def toString: String = s"{set.$set/${reference.toString}#${disambiguator.fold("0")(_.hashCode.toString)}"
-  }
-
-  final case class MultiSetImplId(set: DIKey, impl: ImplDef)
-  object MultiSetImplId {
-    implicit object SetImplIdContract extends IdContract[MultiSetImplId] {
-      override def repr(v: MultiSetImplId): String = s"set/${v.set}#${v.impl.hashCode}"
-    }
-  }
-}
-
-trait IdContract[T] {
-  def repr(v: T): String
-}
-object IdContract {
-  implicit lazy val stringIdContract: IdContract[String] = new IdContractImpl[String]
-  implicit def singletonStringIdContract[S <: String with Singleton]: IdContract[S] = new IdContractImpl[S]
-}
-
-//
-
-trait DIFunction {
-  def parameters: Seq[Association.Parameter]
-  def argTypes: Seq[SafeType]
-  def diKeys: Seq[DIKey]
-
-  def ret: SafeType
-
-  def originalFun: AnyRef
-  def fun: Seq[Any] => Any
-  def arity: Int
-
-  def isGenerated: Boolean
-
-  def unsafeApply(refs: Seq[TypedRef[_]]): Any = {
-    val args = verifyArgs(refs)
-    fun(args)
-  }
-
-  private[this] def verifyArgs(refs: Seq[TypedRef[_]]): Seq[Any] = {
-    val (newArgs, types, typesCmp) = parameters.zip(refs).map {
-      case (param, TypedRef(v, tpe, isByName)) =>
-
-        val newArg = if (param.isByName && !isByName) {
-          () => v
-        } else if (isByName && !param.isByName) {
-          v.asInstanceOf[Function0[Any]].apply()
-        } else v
-
-        (newArg, tpe, tpe <:< param.key.tpe)
-    }.unzip3
-
-    val countOk = refs.size == parameters.size
-    val typesOk = !typesCmp.contains(false)
-
-    if (countOk && typesOk) {
-      newArgs
-    } else {
-      throw new UnsafeCallArgsMismatched(
-        message =
-          s"""Mismatched arguments for unsafe call:
-             | ${if (!typesOk) "Wrong types!" else ""}
-             | ${if (!countOk) s"Expected number of arguments $arity, but got ${refs.size}" else ""}
-             |Expected types [${argTypes.mkString(",")}], got types [${types.mkString(",")}], values: (${newArgs.mkString(",")})""".stripMargin,
-        expected = argTypes,
-        actual = types,
-        actualValues = newArgs,
-      )
-    }
-  }
-}
-
-trait Provider extends DIFunction {
-  def unsafeMap(newRet: SafeType, f: Any => _): Provider
-  def unsafeZip(newRet: SafeType, that: Provider): Provider
-  def addUnused(keys: Seq[DIKey]): Provider
-
-  override final def diKeys: Seq[DIKey] = parameters.map(_.key)
-  override final def argTypes: Seq[SafeType] = parameters.map(_.key.tpe)
-  override final val arity: Int = parameters.size
-
-  private def eqField: AnyRef = if (isGenerated) ret else originalFun
-  override final def equals(obj: Any): Boolean = {
-    obj match {
-      case that: Provider =>
-        eqField == that.eqField
-      case _ =>
-        false
-    }
-  }
-  override final def hashCode(): Int = eqField.hashCode()
-  override final def toString: String = s"$fun(${argTypes.mkString(", ")}): $ret"
-}
-
-object Provider {
-
-  final case class ProviderImpl[+A](
-                                     parameters: Seq[Association.Parameter],
-                                     ret: SafeType,
-                                     originalFun: AnyRef,
-                                     fun: Seq[Any] => Any,
-                                     isGenerated: Boolean,
-                                   ) extends Provider {
-    def this(parameters: Seq[Association.Parameter], ret: SafeType, fun: Seq[Any] => Any, isGenerated: Boolean) =
-      this(parameters, ret, fun, fun, isGenerated)
-
-    override def unsafeApply(refs: Seq[TypedRef[_]]): A =
-      super.unsafeApply(refs).asInstanceOf[A]
-
-    override def unsafeMap(newRet: SafeType, f: Any => _): ProviderImpl[_] =
-      copy(ret = newRet, fun = xs => f.apply(fun(xs)))
-
-    override def addUnused(keys: Seq[DIKey]): Provider =
-      copy(parameters = parameters ++ keys.map(key => Association.Parameter(SymbolInfo("<unused>", key.tpe, isByName = false, wasGeneric = false), key)))
-
-    override def unsafeZip(newRet: SafeType, that: Provider): Provider = {
-      ProviderImpl(
-        parameters ++ that.parameters,
-        newRet,
-        { args0 =>
-          val (args1, args2) = args0.splitAt(arity)
-          fun(args1) -> that.fun(args2)
-        },
-        isGenerated,
-      )
-    }
-  }
-  object ProviderImpl {
-    @inline def apply[A](parameters: Seq[Association.Parameter], ret: SafeType, fun: Seq[Any] => Any, isGenerated: Boolean): ProviderImpl[A] =
-      new ProviderImpl(parameters, ret, fun, isGenerated)
-  }
-
-}
-
-// wiring
-
-sealed trait Wiring {
-  def instanceType: SafeType
-  def associations: Seq[Association]
-  def replaceKeys(f: Association => DIKey.BasicKey): Wiring
-
-  def requiredKeys: Set[DIKey] = associations.map(_.key).toSet
-}
-
-object Wiring {
-  sealed trait SingletonWiring extends Wiring {
-    def instanceType: SafeType
-    override def replaceKeys(f: Association => DIKey.BasicKey): SingletonWiring
-  }
-  object SingletonWiring {
-    final case class Function(provider: Provider, associations: Seq[Association.Parameter]) extends SingletonWiring {
-      override final def instanceType: SafeType = provider.ret
-
-      override final def replaceKeys(f: Association => DIKey.BasicKey): Function = this.copy(associations = this.associations.map(a => a.withKey(f(a))))
-    }
-    final case class Instance(instanceType: SafeType, instance: Any) extends SingletonWiring {
-      override final def associations: Seq[Association] = Seq.empty
-
-      override final def replaceKeys(@unused f: Association => DIKey.BasicKey): Instance = this
-    }
-    final case class Reference(instanceType: SafeType, key: DIKey, weak: Boolean) extends SingletonWiring {
-      override final def associations: Seq[Association] = Seq.empty
-
-      override final val requiredKeys: Set[DIKey] = super.requiredKeys ++ Set(key)
-      override final def replaceKeys(@unused f: Association => DIKey.BasicKey): Reference = this
-    }
-  }
-
-  sealed trait MonadicWiring extends Wiring {
-    def effectWiring: SingletonWiring
-    def effectHKTypeCtor: SafeType
-  }
-  object MonadicWiring {
-    final case class Effect(instanceType: SafeType, effectHKTypeCtor: SafeType, effectWiring: SingletonWiring) extends MonadicWiring {
-      override final def associations: Seq[Association] = effectWiring.associations
-      override final def requiredKeys: Set[DIKey] = effectWiring.requiredKeys
-
-      override final def replaceKeys(f: Association => DIKey.BasicKey): Effect = copy(effectWiring = effectWiring.replaceKeys(f))
-    }
-
-    final case class Resource(instanceType: SafeType, effectHKTypeCtor: SafeType, effectWiring: SingletonWiring) extends MonadicWiring {
-      override final def associations: Seq[Association] = effectWiring.associations
-      override final def requiredKeys: Set[DIKey] = effectWiring.requiredKeys
-
-      override final def replaceKeys(f: Association => DIKey.BasicKey): Resource = copy(effectWiring = effectWiring.replaceKeys(f))
-    }
-  }
-
-}
-
-final case class TypedRef[+T](private val v: T, tpe: SafeType, isByName: Boolean) {
-  def value: T = v match {
-    case d: ByNameDispatcher => d.apply().asInstanceOf[T]
-    case o => o
-  }
-}
-object TypedRef {
-  def apply[T: Tag](value: T): TypedRef[T] = TypedRef(value, SafeType.get[T], isByName = false)
-  def byName[T: Tag](value: => T): TypedRef[T] = TypedRef((() => value).asInstanceOf[T], SafeType.get[T], isByName = true)
-}
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/universe/RuntimeDIUniverse/package.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/universe/RuntimeDIUniverse/package.scala
deleted file mode 100644
index 0de4e118a..000000000
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/reflection/universe/RuntimeDIUniverse/package.scala
+++ /dev/null
@@ -1,7 +0,0 @@
-package izumi.distage.model.reflection.universe
-
-import izumi.fundamentals.platform.functional.Identity
-
-package object RuntimeDIUniverse {
-  lazy val identityEffectType: SafeType = SafeType.getK[Identity]
-}
diff --git a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/CglibNullMethodInterceptor.scala b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/CglibNullMethodInterceptor.scala
index 61331fc11..9e62ecd43 100644
--- a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/CglibNullMethodInterceptor.scala
+++ b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/CglibNullMethodInterceptor.scala
@@ -3,7 +3,7 @@ package izumi.distage.provisioning.strategies.cglib
 import java.lang.reflect.Method
 
 import izumi.distage.model.exceptions.MissingRefException
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 import net.sf.cglib.proxy.{MethodInterceptor, MethodProxy}
 
 // we use this to be able to display something for uninitialized proxies
diff --git a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/CglibProxyProvider.scala b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/CglibProxyProvider.scala
index e97952f97..e0479f010 100644
--- a/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/CglibProxyProvider.scala
+++ b/distage/distage-core-proxy-cglib/src/main/scala/izumi/distage/provisioning/strategies/cglib/CglibProxyProvider.scala
@@ -3,7 +3,7 @@ package izumi.distage.provisioning.strategies.cglib
 import izumi.distage.model.provisioning.proxies.ProxyProvider
 import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyParams.{Empty, Params}
 import izumi.distage.model.provisioning.proxies.ProxyProvider.{DeferredInit, ProxyContext}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 import izumi.distage.provisioning.strategies.cglib.exceptions.CgLibInstantiationOpException
 import net.sf.cglib.proxy.{Callback, Enhancer}
 
diff --git a/distage/distage-core/.js/src/main/scala/izumi/distage/provisioning/strategies/ProxyStrategyDefaultImplPlatformSpecific.scala b/distage/distage-core/.js/src/main/scala/izumi/distage/provisioning/strategies/ProxyStrategyDefaultImplPlatformSpecific.scala
index 605fd2788..985ac6e4d 100644
--- a/distage/distage-core/.js/src/main/scala/izumi/distage/provisioning/strategies/ProxyStrategyDefaultImplPlatformSpecific.scala
+++ b/distage/distage-core/.js/src/main/scala/izumi/distage/provisioning/strategies/ProxyStrategyDefaultImplPlatformSpecific.scala
@@ -6,7 +6,7 @@ import izumi.distage.model.provisioning.ProvisioningKeyProvider
 import izumi.distage.model.provisioning.proxies.ProxyProvider
 import izumi.distage.model.provisioning.proxies.ProxyProvider.DeferredInit
 import izumi.distage.model.reflection.MirrorProvider
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.SafeType
+import izumi.distage.model.reflection.SafeType
 import izumi.fundamentals.platform.language.unused
 
 abstract class ProxyStrategyDefaultImplPlatformSpecific
diff --git a/distage/distage-core/.jvm/src/main/scala/izumi/distage/provisioning/strategies/ProxyStrategyDefaultImplPlatformSpecific.scala b/distage/distage-core/.jvm/src/main/scala/izumi/distage/provisioning/strategies/ProxyStrategyDefaultImplPlatformSpecific.scala
index 5b2b37fc9..0d56d625f 100644
--- a/distage/distage-core/.jvm/src/main/scala/izumi/distage/provisioning/strategies/ProxyStrategyDefaultImplPlatformSpecific.scala
+++ b/distage/distage-core/.jvm/src/main/scala/izumi/distage/provisioning/strategies/ProxyStrategyDefaultImplPlatformSpecific.scala
@@ -2,12 +2,12 @@ package izumi.distage.provisioning.strategies
 
 import izumi.distage.model.exceptions.{MissingRefException, NoRuntimeClassException, UnsupportedOpException}
 import izumi.distage.model.plan.ExecutableOp.{ProxyOp, WiringOp}
+import izumi.distage.model.plan.Wiring
 import izumi.distage.model.provisioning.ProvisioningKeyProvider
 import izumi.distage.model.provisioning.proxies.ProxyProvider
 import izumi.distage.model.provisioning.proxies.ProxyProvider.{DeferredInit, ProxyContext, ProxyParams}
-import izumi.distage.model.reflection.MirrorProvider
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.{DIKey, SafeType, Wiring}
+import izumi.distage.model.reflection.Provider.ProviderType
+import izumi.distage.model.reflection.{Association, DIKey, MirrorProvider, SafeType}
 import izumi.fundamentals.reflection.TypeUtil
 
 abstract class ProxyStrategyDefaultImplPlatformSpecific
@@ -24,8 +24,8 @@ abstract class ProxyStrategyDefaultImplPlatformSpecific
     } else {
       val allArgsAsNull: Array[(Class[_], Any)] = {
         op.op match {
-          case WiringOp.CallProvider(_, Wiring.SingletonWiring.Function(provider, params), _) if provider.isGenerated =>
-            // for generated constructors, try to fetch known dependencies from the object graph
+          case WiringOp.CallProvider(_, Wiring.SingletonWiring.Function(provider, params), _) if provider.providerType eq ProviderType.Class =>
+            // for class constructors, try to fetch known dependencies from the object graph
             params.map(fetchNonforwardRefParamWithClass(context, op.forwardRefs, _)).toArray
           case _ =>
             // otherwise fill everything with nulls
@@ -46,7 +46,7 @@ abstract class ProxyStrategyDefaultImplPlatformSpecific
     throw new UnsupportedOpException(s"Tried to make proxy of non-proxyable (final?) $tpe", op)
   }
 
-  private def fetchNonforwardRefParamWithClass(context: ProvisioningKeyProvider, forwardRefs: Set[DIKey], param: RuntimeDIUniverse.Association.Parameter): (Class[_], Any) = {
+  private def fetchNonforwardRefParamWithClass(context: ProvisioningKeyProvider, forwardRefs: Set[DIKey], param: Association.Parameter): (Class[_], Any) = {
     val clazz: Class[_] = if (param.isByName) {
       classOf[Function0[_]]
     } else if (param.wasGeneric) {
diff --git a/distage/distage-core/src/main/scala/distage/Distage.scala b/distage/distage-core/src/main/scala/distage/Distage.scala
index be1d48427..c326fc1ed 100644
--- a/distage/distage-core/src/main/scala/distage/Distage.scala
+++ b/distage/distage-core/src/main/scala/distage/Distage.scala
@@ -1,7 +1,6 @@
 package distage
 
 import izumi.distage.model.plan.ExecutableOp
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
 import izumi.distage.planning.extensions
 import izumi.distage.{constructors, model, planning}
 import izumi.fundamentals.reflection.Tags
@@ -73,11 +72,11 @@ trait Distage {
   val SemiPlan: model.plan.SemiPlan.type = model.plan.SemiPlan
   type AbstractPlan[OpType <: ExecutableOp] = model.plan.AbstractPlan[OpType]
 
-  type DIKey = RuntimeDIUniverse.DIKey
-  val DIKey: RuntimeDIUniverse.DIKey.type = RuntimeDIUniverse.DIKey
+  type DIKey = model.reflection.DIKey
+  val DIKey: model.reflection.DIKey.type = model.reflection.DIKey
 
-  type SafeType = RuntimeDIUniverse.SafeType
-  val SafeType: RuntimeDIUniverse.SafeType.type = RuntimeDIUniverse.SafeType
+  type SafeType = model.reflection.SafeType
+  val SafeType: model.reflection.SafeType.type = model.reflection.SafeType
 
   type ModuleBase = model.definition.ModuleBase
   val ModuleBase: model.definition.ModuleBase.type = model.definition.ModuleBase
diff --git a/distage/distage-core/src/main/scala/distage/package.scala b/distage/distage-core/src/main/scala/distage/package.scala
index a5b3a3ed4..0a4490aa1 100644
--- a/distage/distage-core/src/main/scala/distage/package.scala
+++ b/distage/distage-core/src/main/scala/distage/package.scala
@@ -1,5 +1,4 @@
 import izumi.distage.model.plan.ExecutableOp
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
 import izumi.distage.planning.extensions
 import izumi.distage.{constructors, model, planning}
 import izumi.fundamentals.reflection.Tags
@@ -71,11 +70,11 @@ package object distage extends Distage {
   override val SemiPlan: model.plan.SemiPlan.type = model.plan.SemiPlan
   override type AbstractPlan[OpType <: ExecutableOp] = model.plan.AbstractPlan[OpType]
 
-  override type DIKey = RuntimeDIUniverse.DIKey
-  override val DIKey: RuntimeDIUniverse.DIKey.type = RuntimeDIUniverse.DIKey
+  override type DIKey = model.reflection.DIKey
+  override val DIKey: model.reflection.DIKey.type = model.reflection.DIKey
 
-  override type SafeType = RuntimeDIUniverse.SafeType
-  override val SafeType: RuntimeDIUniverse.SafeType.type = RuntimeDIUniverse.SafeType
+  override type SafeType = model.reflection.SafeType
+  override val SafeType: model.reflection.SafeType.type = model.reflection.SafeType
 
   override type ModuleBase = model.definition.ModuleBase
   override val ModuleBase: model.definition.ModuleBase.type = model.definition.ModuleBase
diff --git a/distage/distage-core/src/main/scala/izumi/distage/InjectorDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/InjectorDefaultImpl.scala
index 1b0d9d9d4..3aa8d4f8c 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/InjectorDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/InjectorDefaultImpl.scala
@@ -8,7 +8,7 @@ import izumi.distage.model.plan.{OrderedPlan, SemiPlan}
 import izumi.distage.model.provisioning.PlanInterpreter
 import izumi.distage.model.provisioning.PlanInterpreter.{FailedProvision, FinalizerFilter}
 import izumi.distage.model.recursive.Bootloader
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.DIKey
 import izumi.distage.model.{Injector, Locator, Planner, PlannerInput}
 import izumi.fundamentals.reflection.Tags.TagK
 
@@ -47,15 +47,15 @@ class InjectorDefaultImpl
     planner.finish(semiPlan)
   }
 
-  override def truncate(plan: OrderedPlan, roots: Set[RuntimeDIUniverse.DIKey]): OrderedPlan = {
+  override def truncate(plan: OrderedPlan, roots: Set[DIKey]): OrderedPlan = {
     planner.truncate(plan, roots)
   }
 
-  override private[distage] def produceFX[F[_] : TagK : DIEffect](plan: OrderedPlan, filter: FinalizerFilter[F]): DIResourceBase[F, Locator] = {
+  override private[distage] def produceFX[F[_]: TagK: DIEffect](plan: OrderedPlan, filter: FinalizerFilter[F]): DIResourceBase[F, Locator] = {
     produceDetailedFX[F](plan, filter).evalMap(_.throwOnFailure())
   }
 
-  override private[distage] def produceDetailedFX[F[_] : TagK : DIEffect](plan: OrderedPlan, filter: FinalizerFilter[F]): DIResourceBase[F, Either[FailedProvision[F], Locator]] = {
+  override private[distage] def produceDetailedFX[F[_]: TagK: DIEffect](plan: OrderedPlan, filter: FinalizerFilter[F]): DIResourceBase[F, Either[FailedProvision[F], Locator]] = {
     interpreter.instantiate[F](plan, parentContext, filter)
   }
 
diff --git a/distage/distage-core/src/main/scala/izumi/distage/LocatorDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/LocatorDefaultImpl.scala
index 89ab88820..bf039b2e2 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/LocatorDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/LocatorDefaultImpl.scala
@@ -5,17 +5,15 @@ import izumi.distage.model.plan.OrderedPlan
 import izumi.distage.model.provisioning.PlanInterpreter
 import izumi.distage.model.provisioning.Provision.ProvisionImmutable
 import izumi.distage.model.references.IdentifiedRef
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.SafeType
+import izumi.distage.model.reflection.{DIKey, SafeType}
 import izumi.fundamentals.reflection.Tags.TagK
 
-final class LocatorDefaultImpl[F[_]]
-(
+final class LocatorDefaultImpl[F[_]](
   val plan: OrderedPlan,
   val parent: Option[Locator],
   private val dependencyMap: ProvisionImmutable[F],
 ) extends AbstractLocator {
-  override protected def lookupLocalUnsafe(key: RuntimeDIUniverse.DIKey): Option[Any] =
+  override protected def lookupLocalUnsafe(key: DIKey): Option[Any] =
     dependencyMap.get(key)
 
   override def finalizers[F1[_]: TagK]: collection.Seq[PlanInterpreter.Finalizer[F1]] = {
diff --git a/distage/distage-core/src/main/scala/izumi/distage/bootstrap/BootstrapLocator.scala b/distage/distage-core/src/main/scala/izumi/distage/bootstrap/BootstrapLocator.scala
index 23366fb20..812aaa4af 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/bootstrap/BootstrapLocator.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/bootstrap/BootstrapLocator.scala
@@ -14,8 +14,7 @@ import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyProviderFaili
 import izumi.distage.model.provisioning.strategies._
 import izumi.distage.model.provisioning.{PlanInterpreter, ProvisioningFailureInterceptor}
 import izumi.distage.model.references.IdentifiedRef
-import izumi.distage.model.reflection.MirrorProvider
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.{DIKey, MirrorProvider}
 import izumi.distage.planning._
 import izumi.distage.planning.gc.{NoopDIGC, TracingDIGC}
 import izumi.distage.provisioning._
@@ -42,7 +41,7 @@ final class BootstrapLocator(bindings0: BootstrapContextModule, bootstrapActivat
       .bootstrapPlanner(bootstrapActivation)
       .plan(PlannerInput.noGc(bindings))
   }
-  override lazy val index: Map[RuntimeDIUniverse.DIKey, Any] = super.index
+  override lazy val index: Map[DIKey, Any] = super.index
 
   private[this] val bootstrappedContext: Locator = {
     val resource = BootstrapLocator.bootstrapProducer.instantiate[Identity](plan, this, FinalizerFilter.all)
@@ -62,7 +61,7 @@ final class BootstrapLocator(bindings0: BootstrapContextModule, bootstrapActivat
 
   override def finalizers[F[_]: TagK]: collection.Seq[PlanInterpreter.Finalizer[F]] = Nil
 
-  override protected def lookupLocalUnsafe(key: RuntimeDIUniverse.DIKey): Option[Any] = {
+  override protected def lookupLocalUnsafe(key: DIKey): Option[Any] = {
     Option(_instances.get()) match {
       case Some(_) =>
         index.get(key)
diff --git a/distage/distage-core/src/main/scala/izumi/distage/planning/AutoSetHook.scala b/distage/distage-core/src/main/scala/izumi/distage/planning/AutoSetHook.scala
index 05526991f..bc4c1b3d1 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/planning/AutoSetHook.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/planning/AutoSetHook.scala
@@ -2,10 +2,10 @@ package izumi.distage.planning
 
 import izumi.distage.model.definition.ImplDef
 import izumi.distage.model.plan.operations.OperationOrigin
-import izumi.distage.model.plan.{ExecutableOp, OrderedPlan, SemiPlan}
+import izumi.distage.model.plan.{ExecutableOp, OrderedPlan, SemiPlan, Wiring}
 import izumi.distage.model.planning.PlanningHook
 import izumi.distage.model.providers.ProviderMagnet
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.fundamentals.reflection.Tags.Tag
 
 import scala.collection.immutable.ListSet
diff --git a/distage/distage-core/src/main/scala/izumi/distage/planning/BindingTranslator.scala b/distage/distage-core/src/main/scala/izumi/distage/planning/BindingTranslator.scala
index 01cd4183c..60c55e28b 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/planning/BindingTranslator.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/planning/BindingTranslator.scala
@@ -3,12 +3,13 @@ package izumi.distage.planning
 import izumi.distage.model.definition.Binding.{EmptySetBinding, SetElementBinding, SingletonBinding}
 import izumi.distage.model.definition.{Binding, ImplDef}
 import izumi.distage.model.plan.ExecutableOp.{CreateSet, InstantiationOp, MonadicOp, WiringOp}
+import izumi.distage.model.plan.Wiring
+import izumi.distage.model.plan.Wiring.SingletonWiring._
+import izumi.distage.model.plan.Wiring._
 import izumi.distage.model.plan.initial.{NextOps, PrePlan}
 import izumi.distage.model.plan.operations.OperationOrigin
 import izumi.distage.model.planning._
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.Wiring.SingletonWiring._
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.Wiring._
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.{DIKey, Wiring}
+import izumi.distage.model.reflection.DIKey
 
 trait BindingTranslator {
   def computeProvisioning(currentPlan: PrePlan, binding: Binding): NextOps
diff --git a/distage/distage-core/src/main/scala/izumi/distage/planning/ForwardingRefResolverDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/planning/ForwardingRefResolverDefaultImpl.scala
index 07ddd754e..a46209faa 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/planning/ForwardingRefResolverDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/planning/ForwardingRefResolverDefaultImpl.scala
@@ -3,7 +3,7 @@ package izumi.distage.planning
 import izumi.distage.model.plan.ExecutableOp.{ImportDependency, InstantiationOp, ProxyOp}
 import izumi.distage.model.plan.{ExecutableOp, OrderedPlan}
 import izumi.distage.model.planning.{ForwardingRefResolver, PlanAnalyzer}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import distage.Id
 
 import scala.collection.mutable
diff --git a/distage/distage-core/src/main/scala/izumi/distage/planning/PlanAnalyzerDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/planning/PlanAnalyzerDefaultImpl.scala
index a2e92fd06..2abc3129e 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/planning/PlanAnalyzerDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/planning/PlanAnalyzerDefaultImpl.scala
@@ -7,7 +7,7 @@ import izumi.distage.model.plan.topology.DependencyGraph.DependencyKind
 import izumi.distage.model.plan.topology.PlanTopology.PlanTopologyImmutable
 import izumi.distage.model.plan.topology.{DependencyGraph, PlanTopology}
 import izumi.distage.model.planning.PlanAnalyzer
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 
 import scala.collection.mutable
 
diff --git a/distage/distage-core/src/main/scala/izumi/distage/planning/PlannerDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/planning/PlannerDefaultImpl.scala
index f75a7cfb6..6bb5a0587 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/planning/PlannerDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/planning/PlannerDefaultImpl.scala
@@ -10,7 +10,7 @@ import izumi.distage.model.plan.operations.OperationOrigin
 import izumi.distage.model.plan.topology.PlanTopology
 import izumi.distage.model.planning._
 import izumi.distage.model.reflection.MirrorProvider
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 import izumi.distage.model.{Planner, PlannerInput}
 import izumi.distage.planning.gc.TracingDIGC
 import izumi.functional.Value
diff --git a/distage/distage-core/src/main/scala/izumi/distage/planning/PlanningHookAggregate.scala b/distage/distage-core/src/main/scala/izumi/distage/planning/PlanningHookAggregate.scala
index 95db39b46..d0e3350c1 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/planning/PlanningHookAggregate.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/planning/PlanningHookAggregate.scala
@@ -2,16 +2,15 @@ package izumi.distage.planning
 
 import izumi.distage.model.definition.{Binding, ModuleBase}
 import izumi.distage.model.plan.initial.PrePlan
-import izumi.distage.model.plan.{OrderedPlan, SemiPlan}
+import izumi.distage.model.plan.{OrderedPlan, SemiPlan, Wiring}
 import izumi.distage.model.planning.PlanningHook
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
 
 final class PlanningHookAggregate
 (
   hooks: Set[PlanningHook]
 ) extends PlanningHook {
 
-  override def hookWiring(binding: Binding.ImplBinding, wiring: RuntimeDIUniverse.Wiring): RuntimeDIUniverse.Wiring = {
+  override def hookWiring(binding: Binding.ImplBinding, wiring: Wiring): Wiring = {
     hooks.foldLeft(wiring) {
       case (acc, hook) =>
         hook.hookWiring(binding, acc)
diff --git a/distage/distage-core/src/main/scala/izumi/distage/planning/PruningPlanMergingPolicyDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/planning/PruningPlanMergingPolicyDefaultImpl.scala
index e41022c4a..c31c2040d 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/planning/PruningPlanMergingPolicyDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/planning/PruningPlanMergingPolicyDefaultImpl.scala
@@ -7,8 +7,7 @@ import izumi.distage.model.plan._
 import izumi.distage.model.plan.initial.PrePlan
 import izumi.distage.model.planning.PlanMergingPolicy
 import izumi.distage.model.planning.PlanMergingPolicy.{DIKeyConflictResolution, WithResolve}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 import izumi.distage.planning.PruningPlanMergingPolicyDefaultImpl.PlanMergingPolicyDefaultImpl
 import izumi.distage.planning.gc.TracingDIGC
 import izumi.fundamentals.platform.language.unused
@@ -27,7 +26,7 @@ class PruningPlanMergingPolicyDefaultImpl
   protected def logHandleIssues(@unused issues: Map[DIKey, DIKeyConflictResolution.Failed]): Unit = {}
   protected def logPruningSuccesfulResolve(@unused issues: Map[DIKey, DIKeyConflictResolution.Failed], @unused erased: Map[DIKey, Set[SemiplanOp]]): Unit = {}
 
-  override protected def resolveConflict(plan: PrePlan, key: RuntimeDIUniverse.DIKey, operations: Set[PrePlan.JustOp]): DIKeyConflictResolution = {
+  override protected def resolveConflict(plan: PrePlan, key: DIKey, operations: Set[PrePlan.JustOp]): DIKeyConflictResolution = {
     assert(operations.size > 1)
 
     val filtered = operations.filter {
diff --git a/distage/distage-core/src/main/scala/izumi/distage/planning/SanityCheckerDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/planning/SanityCheckerDefaultImpl.scala
index 960b595b1..19ca4b7e0 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/planning/SanityCheckerDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/planning/SanityCheckerDefaultImpl.scala
@@ -4,7 +4,7 @@ import izumi.distage.model.exceptions._
 import izumi.distage.model.plan.ExecutableOp.{CreateSet, ProxyOp}
 import izumi.distage.model.plan.{ExecutableOp, OrderedPlan}
 import izumi.distage.model.planning.{PlanAnalyzer, SanityChecker}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.DIKey
 
 import scala.collection.mutable
 
@@ -41,7 +41,7 @@ class SanityCheckerDefaultImpl
     val (proxies, single) = ops.partition(_.isInstanceOf[ProxyOp.InitProxy])
 
     val (uniqOps, nonUniqueOps) = single
-      .foldLeft((mutable.ArrayBuffer[RuntimeDIUniverse.DIKey](), mutable.HashSet[RuntimeDIUniverse.DIKey]())) {
+      .foldLeft((mutable.ArrayBuffer[DIKey](), mutable.HashSet[DIKey]())) {
         case ((unique, nonunique), s: CreateSet) =>
           (unique, nonunique += s.target)
         case ((unique, nonunique), s) =>
@@ -60,14 +60,14 @@ class SanityCheckerDefaultImpl
     }
   }
 
-  private def assertNoDuplicateKeys(keys: Seq[RuntimeDIUniverse.DIKey]): Unit = {
+  private def assertNoDuplicateKeys(keys: Seq[DIKey]): Unit = {
     val dupes = duplicates(keys)
     if (dupes.nonEmpty) {
       throw new DuplicateKeysException(s"Cannot finish the plan, there are duplicates: $dupes!", dupes)
     }
   }
 
-  private def duplicates(keys: Seq[RuntimeDIUniverse.DIKey]): Map[RuntimeDIUniverse.DIKey, Int] = {
+  private def duplicates(keys: Seq[DIKey]): Map[DIKey, Int] = {
     val counted = keys
       .groupBy(k => k)
       .map(t => (t._1, t._2.length))
diff --git a/distage/distage-core/src/main/scala/izumi/distage/planning/extensions/GraphDumpObserver.scala b/distage/distage-core/src/main/scala/izumi/distage/planning/extensions/GraphDumpObserver.scala
index e766d611c..b252f4cb0 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/planning/extensions/GraphDumpObserver.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/planning/extensions/GraphDumpObserver.scala
@@ -10,7 +10,6 @@ import izumi.distage.model.plan.initial.PrePlan
 import izumi.distage.model.plan.repr.KeyMinimizer
 import izumi.distage.model.plan.{OrderedPlan => _, SemiPlan => _, _}
 import izumi.distage.model.planning.{PlanAnalyzer, PlanningObserver}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
 import izumi.distage.planning.extensions.GraphDumpObserver.RenderedDot
 import izumi.fundamentals.graphs.dotml.Digraph
 import izumi.fundamentals.platform.language.Quirks._
@@ -151,11 +150,11 @@ final class GraphDumpObserver
             "newset"
           case op: ExecutableOp.WiringOp =>
             op.wiring match {
-              case RuntimeDIUniverse.Wiring.SingletonWiring.Function(_, _) =>
+              case Wiring.SingletonWiring.Function(_, _) =>
                 "lambda"
-              case RuntimeDIUniverse.Wiring.SingletonWiring.Instance(_, _) =>
+              case Wiring.SingletonWiring.Instance(_, _) =>
                 "instance"
-              case RuntimeDIUniverse.Wiring.SingletonWiring.Reference(_, _, weak) =>
+              case Wiring.SingletonWiring.Reference(_, _, weak) =>
                 if (weak) {
                   attrs.put("style", "filled,dashed")
                 }
diff --git a/distage/distage-core/src/main/scala/izumi/distage/planning/gc/TracingDIGC.scala b/distage/distage-core/src/main/scala/izumi/distage/planning/gc/TracingDIGC.scala
index b0094f91e..5e531c632 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/planning/gc/TracingDIGC.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/planning/gc/TracingDIGC.scala
@@ -1,9 +1,9 @@
 package izumi.distage.planning.gc
 
 import izumi.distage.model.plan.ExecutableOp._
-import izumi.distage.model.plan.{ExecutableOp, GCMode, SemiPlan}
+import izumi.distage.model.plan.{ExecutableOp, GCMode, SemiPlan, Wiring}
 import izumi.distage.model.planning.DIGarbageCollector
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.fundamentals.graphs.AbstractGCTracer
 
 import scala.collection.mutable
diff --git a/distage/distage-core/src/main/scala/izumi/distage/provisioning/LocatorContext.scala b/distage/distage-core/src/main/scala/izumi/distage/provisioning/LocatorContext.scala
index 19a1d5db8..41da7056c 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/provisioning/LocatorContext.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/provisioning/LocatorContext.scala
@@ -3,7 +3,7 @@ package izumi.distage.provisioning
 import izumi.distage.model.Locator
 import izumi.distage.model.provisioning.proxies.ProxyDispatcher.ByNameDispatcher
 import izumi.distage.model.provisioning.{Provision, ProvisioningKeyProvider}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 
 final case class LocatorContext
 (
diff --git a/distage/distage-core/src/main/scala/izumi/distage/provisioning/PlanInterpreterDefaultRuntimeImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/provisioning/PlanInterpreterDefaultRuntimeImpl.scala
index 3e87bb4b3..744724cda 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/provisioning/PlanInterpreterDefaultRuntimeImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/provisioning/PlanInterpreterDefaultRuntimeImpl.scala
@@ -13,7 +13,7 @@ import izumi.distage.model.provisioning.PlanInterpreter.{FailedProvision, Finali
 import izumi.distage.model.provisioning.Provision.ProvisionMutable
 import izumi.distage.model.provisioning._
 import izumi.distage.model.provisioning.strategies._
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.distage.model.recursive.LocatorRef
 import izumi.fundamentals.reflection.Tags.TagK
 
@@ -206,7 +206,7 @@ class PlanInterpreterDefaultRuntimeImpl
     F.traverse_(monadicOps) {
       op =>
         val actionEffectType = op.effectHKTypeCtor
-        val isEffect = actionEffectType != identityEffectType
+        val isEffect = actionEffectType != SafeType.identityEffectType
 
         if (isEffect && !(actionEffectType <:< provisionerEffectType)) {
           addFailure(ProvisioningFailure(op, new IncompatibleEffectTypesException(provisionerEffectType, actionEffectType)))
diff --git a/distage/distage-core/src/main/scala/izumi/distage/provisioning/ProvisionOperationVerifier.scala b/distage/distage-core/src/main/scala/izumi/distage/provisioning/ProvisionOperationVerifier.scala
index 7e4d00660..71f1f38ec 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/provisioning/ProvisionOperationVerifier.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/provisioning/ProvisionOperationVerifier.scala
@@ -4,7 +4,7 @@ import izumi.distage.model.exceptions._
 import izumi.distage.model.provisioning.proxies.ProxyDispatcher
 import izumi.distage.model.provisioning.proxies.ProxyDispatcher.ByNameDispatcher
 import izumi.distage.model.reflection.MirrorProvider
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 import izumi.fundamentals.platform.language.Quirks
 
 trait ProvisionOperationVerifier {
diff --git a/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/EffectStrategyDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/EffectStrategyDefaultImpl.scala
index f92957338..24f7db0ea 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/EffectStrategyDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/EffectStrategyDefaultImpl.scala
@@ -6,7 +6,7 @@ import izumi.distage.model.exceptions.{IncompatibleEffectTypesException, Missing
 import izumi.distage.model.plan.ExecutableOp.MonadicOp
 import izumi.distage.model.provisioning.strategies.EffectStrategy
 import izumi.distage.model.provisioning.{NewObjectOp, OperationExecutor, ProvisioningKeyProvider}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.{SafeType, identityEffectType}
+import izumi.distage.model.reflection.SafeType
 import izumi.fundamentals.platform.language.unused
 import izumi.fundamentals.reflection.Tags.TagK
 
@@ -20,7 +20,7 @@ class EffectStrategyDefaultImpl
     val provisionerEffectType = SafeType.getK[F]
     val actionEffectType = op.effectHKTypeCtor
 
-    val isEffect = actionEffectType != identityEffectType
+    val isEffect = actionEffectType != SafeType.identityEffectType
     if (isEffect && !(actionEffectType <:< provisionerEffectType)) {
       throw new IncompatibleEffectTypesException(provisionerEffectType, actionEffectType)
     }
diff --git a/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/ProviderStrategyDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/ProviderStrategyDefaultImpl.scala
index da665349a..dd411c271 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/ProviderStrategyDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/ProviderStrategyDefaultImpl.scala
@@ -4,17 +4,17 @@ import izumi.distage.model.exceptions.InvalidPlanException
 import izumi.distage.model.plan.ExecutableOp.WiringOp
 import izumi.distage.model.provisioning.strategies.ProviderStrategy
 import izumi.distage.model.provisioning.{NewObjectOp, ProvisioningKeyProvider, WiringExecutor}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.TypedRef
 import izumi.fundamentals.platform.language.unused
 
 class ProviderStrategyDefaultImpl extends ProviderStrategy  {
   def callProvider(context: ProvisioningKeyProvider, @unused executor: WiringExecutor, op: WiringOp.CallProvider): Seq[NewObjectOp.NewInstance] = {
 
-    val args: Vector[RuntimeDIUniverse.TypedRef[_]] = op.wiring.associations.map {
+    val args: Vector[TypedRef[_]] = op.wiring.associations.map {
       param =>
         context.fetchKey(param.key, param.isByName) match {
           case Some(dep) =>
-            RuntimeDIUniverse.TypedRef(dep, param.key.tpe, param.isByName)
+            TypedRef(dep, param.key.tpe, param.isByName)
           case _ =>
             throw new InvalidPlanException("The impossible happened! Tried to instantiate class," +
                 s" but the dependency has not been initialized: Class: $op.target, dependency: $param")
diff --git a/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/ProxyStrategyDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/ProxyStrategyDefaultImpl.scala
index ee4cfc0a3..c3f08b8c5 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/ProxyStrategyDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/ProxyStrategyDefaultImpl.scala
@@ -10,7 +10,7 @@ import izumi.distage.model.provisioning.proxies.{ProxyDispatcher, ProxyProvider}
 import izumi.distage.model.provisioning.strategies._
 import izumi.distage.model.provisioning.{NewObjectOp, OperationExecutor, ProvisioningKeyProvider, WiringExecutor}
 import izumi.distage.model.reflection.MirrorProvider
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.distage.provisioning.strategies.ProxyStrategyDefaultImpl.FakeSet
 import izumi.fundamentals.platform.language.unused
 import izumi.fundamentals.reflection.Tags.TagK
diff --git a/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/ResourceStrategyDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/ResourceStrategyDefaultImpl.scala
index 72e1f94db..b242b8b40 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/ResourceStrategyDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/ResourceStrategyDefaultImpl.scala
@@ -7,7 +7,7 @@ import izumi.distage.model.exceptions.{IncompatibleEffectTypesException, Missing
 import izumi.distage.model.plan.ExecutableOp.MonadicOp
 import izumi.distage.model.provisioning.strategies.ResourceStrategy
 import izumi.distage.model.provisioning.{NewObjectOp, OperationExecutor, ProvisioningKeyProvider}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.{SafeType, identityEffectType}
+import izumi.distage.model.reflection.SafeType
 import izumi.fundamentals.platform.functional.Identity
 import izumi.fundamentals.platform.language.unused
 import izumi.fundamentals.reflection.Tags.TagK
@@ -22,7 +22,7 @@ class ResourceStrategyDefaultImpl
     val provisionerEffectType = SafeType.getK[F]
     val actionEffectType = op.effectHKTypeCtor
 
-    val isEffect = actionEffectType != identityEffectType
+    val isEffect = actionEffectType != SafeType.identityEffectType
     if (isEffect && !(actionEffectType <:< provisionerEffectType)) {
       throw new IncompatibleEffectTypesException(provisionerEffectType, actionEffectType)
     }
diff --git a/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/SetStrategyDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/SetStrategyDefaultImpl.scala
index 88d94570e..bd048d8f8 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/SetStrategyDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/provisioning/strategies/SetStrategyDefaultImpl.scala
@@ -4,7 +4,7 @@ import izumi.distage.model.exceptions.{IncompatibleTypesException, MissingRefExc
 import izumi.distage.model.plan.ExecutableOp.CreateSet
 import izumi.distage.model.provisioning.strategies.SetStrategy
 import izumi.distage.model.provisioning.{NewObjectOp, ProvisioningKeyProvider, WiringExecutor}
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.fundamentals.platform.language.unused
 
 import scala.collection.immutable.ListSet
diff --git a/distage/distage-extension-config/src/main/scala/izumi/distage/config/codec/DIConfigReader.scala b/distage/distage-extension-config/src/main/scala/izumi/distage/config/codec/DIConfigReader.scala
index e7a6c2345..1195a0e26 100644
--- a/distage/distage-extension-config/src/main/scala/izumi/distage/config/codec/DIConfigReader.scala
+++ b/distage/distage-extension-config/src/main/scala/izumi/distage/config/codec/DIConfigReader.scala
@@ -4,6 +4,7 @@ import com.typesafe.config.{Config, ConfigValue}
 import izumi.distage.config.model.AppConfig
 import izumi.distage.config.model.exceptions.DIConfigReadException
 import izumi.fundamentals.reflection.Tags.Tag
+import pureconfig.ConfigReader
 import pureconfig.error.ConfigReaderException
 
 import scala.reflect.ClassTag
@@ -80,21 +81,23 @@ trait DIConfigReader[A] {
 object DIConfigReader extends LowPriorityDIConfigReaderInstances {
   @inline def apply[T: DIConfigReader]: DIConfigReader[T] = implicitly
 
-  @inline def derive[T: ClassTag](implicit dec: PureconfigAutoDerive[T]): DIConfigReader[T] = {
+  def derived[T: ClassTag](implicit dec: PureconfigAutoDerive[T]): DIConfigReader[T] =
     DIConfigReader.deriveFromPureconfigConfigReader[T](implicitly, dec.value)
-  }
 
-  implicit def deriveFromPureconfigConfigReader[T: ClassTag](implicit dec: pureconfig.ConfigReader[T]): DIConfigReader[T] = {
+  implicit def deriveFromPureconfigConfigReader[T: ClassTag](implicit dec: ConfigReader[T]): DIConfigReader[T] = {
     cv =>
       dec.from(cv) match {
         case Left(errs) => Failure(ConfigReaderException[T](errs))
         case Right(value) => Success(value)
       }
   }
+
+  @deprecated("Use derived", "will be removed in 0.10.3")
+  def derive[T: ClassTag](implicit dec: PureconfigAutoDerive[T]): DIConfigReader[T] = derived[T]
 }
 
-trait LowPriorityDIConfigReaderInstances {
-  @inline implicit def deriveFromPureconfigAutoDerive[T: ClassTag](implicit dec: PureconfigAutoDerive[T]): DIConfigReader[T] = {
+sealed trait LowPriorityDIConfigReaderInstances {
+  implicit final def deriveFromPureconfigAutoDerive[T: ClassTag](implicit dec: PureconfigAutoDerive[T]): DIConfigReader[T] = {
     DIConfigReader.deriveFromPureconfigConfigReader(implicitly, dec.value)
   }
 }
diff --git a/distage/distage-extension-config/src/main/scala/izumi/distage/config/codec/PureconfigAutoDerive.scala b/distage/distage-extension-config/src/main/scala/izumi/distage/config/codec/PureconfigAutoDerive.scala
index 5c177223b..9a9532b01 100644
--- a/distage/distage-extension-config/src/main/scala/izumi/distage/config/codec/PureconfigAutoDerive.scala
+++ b/distage/distage-extension-config/src/main/scala/izumi/distage/config/codec/PureconfigAutoDerive.scala
@@ -1,13 +1,15 @@
 package izumi.distage.config.codec
 
+import pureconfig.ConfigReader
+
 import scala.language.experimental.macros
 import scala.reflect.macros.blackbox
 
 /** Derive `pureconfig.ConfigReader` for A and for its fields recursively with `pureconfig-magnolia` */
-final class PureconfigAutoDerive[A](val value: pureconfig.ConfigReader[A]) extends AnyVal
+final class PureconfigAutoDerive[A](val value: ConfigReader[A]) extends AnyVal
 
 object PureconfigAutoDerive {
-  @inline def apply[A](implicit ev: PureconfigAutoDerive[A]): pureconfig.ConfigReader[A] = ev.value
+  @inline def apply[A](implicit ev: PureconfigAutoDerive[A]): ConfigReader[A] = ev.value
 
   implicit def materialize[A]: PureconfigAutoDerive[A] = macro PureconfigAutoDeriveMacro.materializeImpl[A]
 
diff --git a/distage/distage-extension-config/src/main/scala/izumi/distage/config/codec/PureconfigInstances.scala b/distage/distage-extension-config/src/main/scala/izumi/distage/config/codec/PureconfigInstances.scala
index 84abd6ae7..bfbd6429a 100644
--- a/distage/distage-extension-config/src/main/scala/izumi/distage/config/codec/PureconfigInstances.scala
+++ b/distage/distage-extension-config/src/main/scala/izumi/distage/config/codec/PureconfigInstances.scala
@@ -12,7 +12,7 @@ import scala.util.control.NonFatal
 object PureconfigInstances extends PureconfigInstances
 trait PureconfigInstances {
   /** Override pureconfig's default `snake-case` fields – force CamelCase product-hint */
-  implicit def forceCamelCaseProductHint[T]: ProductHint[T] = camelCaseProductHint.asInstanceOf[ProductHint[T]]
+  @inline implicit final def forceCamelCaseProductHint[T]: ProductHint[T] = camelCaseProductHint.asInstanceOf[ProductHint[T]]
 
   /** Override pureconfig's default `type` field type discriminator for sealed traits.
     * Instead, use `circe`-like format with a single-key object. Example:
@@ -33,10 +33,10 @@ trait PureconfigInstances {
     *   }
     * }}}
     */
-  implicit def forceCirceLikeCoproductHint[T]: CoproductHint[T] = circeLikeCoproductHint.asInstanceOf[CoproductHint[T]]
+  @inline implicit final def forceCirceLikeCoproductHint[T]: CoproductHint[T] = circeLikeCoproductHint.asInstanceOf[CoproductHint[T]]
 
-  private[this] val camelCaseProductHint: ProductHint[Any] = ProductHint(fieldMapping = ConfigFieldMapping(CamelCase, CamelCase))
-  private[this] val circeLikeCoproductHint: CoproductHint[Any] = new CoproductHint[Any] {
+  private[this] final val camelCaseProductHint: ProductHint[Any] = ProductHint(fieldMapping = ConfigFieldMapping(CamelCase, CamelCase))
+  private[this] final val circeLikeCoproductHint: CoproductHint[Any] = new CoproductHint[Any] {
     override def from(cur: ConfigCursor, name: String): Result[Option[ConfigCursor]] = {
       for {
         objCur <- cur.asObjectCursor
@@ -50,10 +50,11 @@ trait PureconfigInstances {
   }
 
   // use `Exported` so that if user imports their own instances, user instances will have higher priority
-  implicit final val memorySizeDecoder: Exported[pureconfig.ConfigReader[ConfigMemorySize]] = Exported((cur: ConfigCursor) => {
-    try Right(cur.value.atKey("m").getMemorySize("m")) catch {
-      case NonFatal(ex) =>
-        Result.fail(error.ConvertFailure(CannotConvert(cur.value.toString, classTag[ConfigMemorySize].toString, ex.toString), cur))
-    }
-  })
+  implicit final lazy val memorySizeDecoder: Exported[ConfigReader[ConfigMemorySize]] = Exported {
+    cur: ConfigCursor =>
+      try Right(cur.value.atKey("m").getMemorySize("m")) catch {
+        case NonFatal(ex) =>
+          Result.fail(error.ConvertFailure(CannotConvert(cur.value.toString, classTag[ConfigMemorySize].toString, ex.toString), cur))
+      }
+  }
 }
diff --git a/distage/distage-extension-config/src/main/scala/izumi/distage/config/extractor/ConfigPathExtractor.scala b/distage/distage-extension-config/src/main/scala/izumi/distage/config/extractor/ConfigPathExtractor.scala
index 56c468492..1427b389f 100644
--- a/distage/distage-extension-config/src/main/scala/izumi/distage/config/extractor/ConfigPathExtractor.scala
+++ b/distage/distage-extension-config/src/main/scala/izumi/distage/config/extractor/ConfigPathExtractor.scala
@@ -6,8 +6,8 @@ import izumi.distage.model.definition.BindingTag.ConfTag
 import izumi.distage.model.plan.operations.OperationOrigin
 import izumi.distage.model.plan.{ExecutableOp, SemiPlan}
 import izumi.distage.model.planning.PlanningHook
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.Wiring.SingletonWiring.Instance
+import izumi.distage.model.reflection.DIKey
+import izumi.distage.model.plan.Wiring.SingletonWiring.Instance
 
 import scala.jdk.CollectionConverters._
 
diff --git a/distage/distage-framework-api/src/main/scala/izumi/distage/roles/model/meta/RoleBinding.scala b/distage/distage-framework-api/src/main/scala/izumi/distage/roles/model/meta/RoleBinding.scala
index 885fe9086..974a7f155 100644
--- a/distage/distage-framework-api/src/main/scala/izumi/distage/roles/model/meta/RoleBinding.scala
+++ b/distage/distage-framework-api/src/main/scala/izumi/distage/roles/model/meta/RoleBinding.scala
@@ -1,7 +1,7 @@
 package izumi.distage.roles.model.meta
 
 import izumi.distage.model.definition.Binding
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.distage.roles.model.RoleDescriptor
 import izumi.fundamentals.platform.resources.IzArtifact
 
diff --git a/distage/distage-framework-api/src/main/scala/izumi/distage/roles/model/meta/RolesInfo.scala b/distage/distage-framework-api/src/main/scala/izumi/distage/roles/model/meta/RolesInfo.scala
index b544c384c..384507172 100644
--- a/distage/distage-framework-api/src/main/scala/izumi/distage/roles/model/meta/RolesInfo.scala
+++ b/distage/distage-framework-api/src/main/scala/izumi/distage/roles/model/meta/RolesInfo.scala
@@ -1,6 +1,6 @@
 package izumi.distage.roles.model.meta
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.DIKey
+import izumi.distage.model.reflection.DIKey
 import izumi.functional.Renderable
 
 final case class RolesInfo(
diff --git a/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/DockerContainer.scala b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/DockerContainer.scala
index 3b40df9c5..948e1e68b 100644
--- a/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/DockerContainer.scala
+++ b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/DockerContainer.scala
@@ -4,10 +4,9 @@ import java.util.concurrent.TimeUnit
 
 import com.github.dockerjava.api.command.InspectContainerResponse
 import com.github.dockerjava.api.model._
-import com.github.dockerjava.core.command.PullImageResultCallback
 import com.github.ghik.silencer.silent
 import distage.TagK
-import izumi.distage.docker.Docker.{AvailablePort, ClientConfig, ContainerConfig, ContainerId, DockerPort, HealthCheckResult, Mount, ServicePort}
+import izumi.distage.docker.Docker._
 import izumi.distage.framework.model.exceptions.IntegrationCheckException
 import izumi.distage.model.definition.DIResource
 import izumi.distage.model.effect.DIEffect.syntax._
@@ -25,7 +24,7 @@ trait ContainerDef {
   self =>
   type Tag
   type Container = DockerContainer[Tag]
-  type Config = ContainerConfig[Tag]
+  type Config = Docker.ContainerConfig[Tag]
 
   def config: Config
 
@@ -66,8 +65,9 @@ object ContainerDef {
 final case class DockerContainer[Tag](
   id: Docker.ContainerId,
   name: String,
+  hostName: String,
   ports: Map[Docker.DockerPort, Seq[ServicePort]],
-  containerConfig: ContainerConfig[Tag],
+  containerConfig: Docker.ContainerConfig[Tag],
   clientConfig: ClientConfig,
   availablePorts: Map[Docker.DockerPort, Seq[AvailablePort]],
 ) {
@@ -92,7 +92,7 @@ object DockerContainer {
   private[this] final case class PortDecl(port: DockerPort, localFree: Int, binding: PortBinding, labels: Map[String, String])
 
   final class Resource[F[_]: DIEffect: DIEffectAsync, T](
-    config: ContainerConfig[T],
+    config: Docker.ContainerConfig[T],
     clientw: DockerClientWrapper[F],
     logger: IzLogger,
   ) extends DIResource[F, DockerContainer[T]] {
@@ -108,7 +108,7 @@ object DockerContainer {
       }
     }
 
-    private[this] def shouldReuse(config: ContainerConfig[T]): Boolean = {
+    private[this] def shouldReuse(config: Docker.ContainerConfig[T]): Boolean = {
       config.reuse && clientw.clientConfig.allowReuse
     }
 
@@ -220,6 +220,7 @@ object DockerContainer {
               containerConfig = config,
               clientConfig = clientw.clientConfig,
               availablePorts = Map.empty,
+              hostName = inspection.getConfig.getHostName
             )
             await(unverified)
           case None =>
@@ -228,7 +229,6 @@ object DockerContainer {
       } yield existing
     }
 
-    @silent("deprecated")
     private[this] def doRun(ports: Seq[PortDecl]): F[DockerContainer[T]] = {
       val allPortLabels = ports.flatMap(p => p.labels).toMap
       val baseCmd = client
@@ -236,12 +236,13 @@ object DockerContainer {
         .withLabels((clientw.labels ++ allPortLabels).asJava)
 
       val volumes = config.mounts.map {
-        case Mount(h, c, true) => new Bind(h, new Volume(c), true)
-        case Mount(h, c, _) => new Bind(h, new Volume(c))
+        case Docker.Mount(h, c, true) => new Bind(h, new Volume(c), true)
+        case Docker.Mount(h, c, _) => new Bind(h, new Volume(c))
       }
 
       for {
         out <- DIEffect[F].maybeSuspend {
+          @silent("method.*Bind.*deprecated")
           val cmd = Value(baseCmd)
             .mut(config.name) { case (n, c) => c.withName(n) }
             .mut(ports.nonEmpty)(_.withExposedPorts(ports.map(_.binding.getExposedPort).asJava))
@@ -260,7 +261,7 @@ object DockerContainer {
           logger.info(s"Going to pull `${config.image}`...")
           client
             .pullImageCmd(config.image)
-            .exec(new PullImageResultCallback())
+            .start()
             .awaitCompletion(config.pullTimeout.toMillis, TimeUnit.MILLISECONDS);
 
           logger.debug(s"Going to create container from image `${config.image}`...")
@@ -270,6 +271,7 @@ object DockerContainer {
           client.startContainerCmd(res.getId).exec()
 
           val inspection = client.inspectContainerCmd(res.getId).exec()
+          val hostName = inspection.getConfig.getHostName
           val maybeMappedPorts = mapContainerPorts(inspection)
 
           maybeMappedPorts match {
@@ -277,7 +279,7 @@ object DockerContainer {
               throw new RuntimeException(s"Created container from `${config.image}` with ${res.getId -> "id"}, but ports are missing: $value!")
 
             case Right(mappedPorts) =>
-              val container = DockerContainer[T](ContainerId(res.getId), inspection.getName, mappedPorts, config, clientw.clientConfig, Map.empty)
+              val container = DockerContainer[T](ContainerId(res.getId), inspection.getName, hostName, mappedPorts, config, clientw.clientConfig, Map.empty)
               logger.debug(s"Created $container from ${config.image}...")
 
               if (config.networks.nonEmpty) {
diff --git a/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/CassandraDocker.scala b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/CassandraDocker.scala
new file mode 100644
index 000000000..32a3bc15e
--- /dev/null
+++ b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/CassandraDocker.scala
@@ -0,0 +1,23 @@
+package izumi.distage.docker.examples
+
+import izumi.distage.docker.ContainerDef
+import izumi.distage.docker.Docker.{ContainerConfig, DockerPort}
+import izumi.distage.model.definition.ModuleDef
+import izumi.fundamentals.reflection.Tags.TagK
+
+object CassandraDocker extends ContainerDef {
+  val primaryPort: DockerPort = DockerPort.TCP(9042)
+
+  override def config: Config = {
+    ContainerConfig(
+      image = "cassandra:3.11.6",
+      ports = Seq(primaryPort)
+    )
+  }
+}
+
+class CassandraDockerModule[F[_]: TagK] extends ModuleDef {
+  make[CassandraDocker.Container].fromResource {
+    CassandraDocker.make[F]
+  }
+}
diff --git a/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/KafkaDocker.scala b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/KafkaDocker.scala
new file mode 100644
index 000000000..33b929d3c
--- /dev/null
+++ b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/KafkaDocker.scala
@@ -0,0 +1,29 @@
+package izumi.distage.docker.examples
+
+import distage.{ModuleDef, TagK}
+import izumi.distage.docker.Docker.{ContainerConfig, DockerPort}
+import izumi.distage.docker.{ContainerDef, DockerClientWrapper, DockerContainer}
+import izumi.distage.model.effect.{DIEffect, DIEffectAsync}
+import izumi.logstage.api.IzLogger
+
+object KafkaDocker extends ContainerDef {
+  val primaryPort: DockerPort.TCP = DockerPort.TCP(9092)
+  override def config: Config = {
+    ContainerConfig(
+      image = "wurstmeister/kafka:2.12-2.4.1",
+      ports = Seq(primaryPort),
+      env = Map(
+        "KAFKA_ADVERTISED_HOST_NAME" -> "127.0.0.1"
+      ),
+      networks = Seq(ZookeeperDocker.zookeeperNetwork),
+    )
+  }
+}
+
+class KafkaDockerModule[F[_]: TagK] extends ModuleDef {
+  make[KafkaDocker.Container].fromResource {
+    (zookeeperDocker: ZookeeperDocker.Container, wr: DockerClientWrapper[F], log: IzLogger, eff: DIEffect[F], effAsync: DIEffectAsync[F]) =>
+      val zkEnv = KafkaDocker.config.env ++ Map("KAFKA_ZOOKEEPER_CONNECT" -> s"${zookeeperDocker.hostName}:2181")
+      new DockerContainer.Resource[F, KafkaDocker.Tag](KafkaDocker.config.copy(env = zkEnv), wr, log)(eff, effAsync)
+  }
+}
diff --git a/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/ZookkeeperDocker.scala b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/ZookkeeperDocker.scala
new file mode 100644
index 000000000..096fc0ee2
--- /dev/null
+++ b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/ZookkeeperDocker.scala
@@ -0,0 +1,22 @@
+package izumi.distage.docker.examples
+
+import distage.{ModuleDef, TagK}
+import izumi.distage.docker.ContainerDef
+import izumi.distage.docker.Docker.{ContainerConfig, ContainerNetwork, DockerPort}
+
+object ZookeeperDocker extends ContainerDef {
+  val zookeeperNetwork: ContainerNetwork = ContainerNetwork("zookeeper-network")
+  override def config: Config = {
+    ContainerConfig(
+      image = "zookeeper:3.4.14",
+      ports = Seq(DockerPort.TCP(2181), DockerPort.TCP(2888), DockerPort.TCP(3888)),
+      networks = Seq(zookeeperNetwork),
+    )
+  }
+}
+
+class ZookeeperDockerModule[F[_]: TagK] extends ModuleDef {
+  make[ZookeeperDocker.Container].fromResource {
+    ZookeeperDocker.make[F]
+  }
+}
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/effect/modules/ZIODIEffectModule.scala b/distage/distage-framework/src/main/scala/izumi/distage/effect/modules/ZIODIEffectModule.scala
index 3191742d1..12113fa43 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/effect/modules/ZIODIEffectModule.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/effect/modules/ZIODIEffectModule.scala
@@ -58,7 +58,7 @@ trait ZIODIEffectModule extends ModuleDef {
     r: zio.clock.Clock => BIOTemporalInstances.BIOTemporalZio[Any](r)
   }
 
-  make[zio.clock.Clock].from(zio.clock.compatrc18.zio_Clock_Live.live)
+  make[zio.clock.Clock].from(zio.Has(zio.clock.Clock.Service.live))
 
   make[zio.Runtime[Any]].from((_: ZIORunner).runtime)
   make[BIORunner[IO]].using[ZIORunner]
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/framework/services/ResourceRewriter.scala b/distage/distage-framework/src/main/scala/izumi/distage/framework/services/ResourceRewriter.scala
index f365a0174..e7130db02 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/framework/services/ResourceRewriter.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/framework/services/ResourceRewriter.scala
@@ -8,7 +8,7 @@ import izumi.distage.model.definition.DIResource.makeSimple
 import izumi.distage.model.definition.ImplDef.DirectImplDef
 import izumi.distage.model.definition._
 import izumi.distage.model.planning.PlanningHook
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.{DIKey, SafeType}
+import izumi.distage.model.reflection.{DIKey, SafeType}
 import izumi.fundamentals.platform.functional.Identity
 import izumi.fundamentals.platform.language.SourceFilePosition
 import izumi.fundamentals.reflection.Tags.Tag
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/roles/bundled/ConfigWriter.scala b/distage/distage-framework/src/main/scala/izumi/distage/roles/bundled/ConfigWriter.scala
index d6b950ce6..a0f690312 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/roles/bundled/ConfigWriter.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/roles/bundled/ConfigWriter.scala
@@ -11,7 +11,7 @@ import izumi.distage.model.definition.Id
 import izumi.distage.model.effect.DIEffect
 import izumi.distage.model.plan.ExecutableOp.WiringOp
 import izumi.distage.model.plan.OrderedPlan
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.Wiring.SingletonWiring.Instance
+import izumi.distage.model.plan.Wiring.SingletonWiring.Instance
 import izumi.distage.roles.bundled.ConfigWriter.{ConfigurableComponent, WriteReference}
 import izumi.distage.roles.model.meta.{RoleBinding, RolesInfo}
 import izumi.distage.roles.model.{RoleDescriptor, RoleTask}
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/roles/logger/SimpleLoggerConfigurator.scala b/distage/distage-framework/src/main/scala/izumi/distage/roles/logger/SimpleLoggerConfigurator.scala
index 09f9fb137..8d7f903e4 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/roles/logger/SimpleLoggerConfigurator.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/roles/logger/SimpleLoggerConfigurator.scala
@@ -77,6 +77,6 @@ object SimpleLoggerConfigurator {
                                 layout: Option[String],
                               )
   object SinksConfig {
-    implicit val configReader: DIConfigReader[SinksConfig] = DIConfigReader.derive
+    implicit val configReader: DIConfigReader[SinksConfig] = DIConfigReader.derived
   }
 }
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/roles/services/RoleProvider.scala b/distage/distage-framework/src/main/scala/izumi/distage/roles/services/RoleProvider.scala
index 4f4f59bb2..f307a6b1b 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/roles/services/RoleProvider.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/roles/services/RoleProvider.scala
@@ -3,7 +3,7 @@ package izumi.distage.roles.services
 import distage._
 import izumi.distage.model.definition.Binding
 import izumi.distage.model.definition.Binding.ImplBinding
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.SafeType
+import izumi.distage.model.reflection.SafeType
 import izumi.distage.roles.model.exceptions.DIAppBootstrapException
 import izumi.distage.roles.model.meta
 import izumi.distage.roles.model.meta.{RoleBinding, RolesInfo}
diff --git a/doc/microsite/src/main/tut/distage/advanced-features.md b/doc/microsite/src/main/tut/distage/advanced-features.md
index 854c7f169..aeb9ebde1 100644
--- a/doc/microsite/src/main/tut/distage/advanced-features.md
+++ b/doc/microsite/src/main/tut/distage/advanced-features.md
@@ -325,6 +325,63 @@ Injector()
 
 Since version `0.10`, support for path-dependent types with a non-value (type) prefix hasn't reimplemented after a rewrite of the internals, see issue: https://github.com/7mind/izumi/issues/764
 
+However, there's a gotcha with value prefixes, when seen by distage they're based on the **literal variable name** of the prefix,
+not the full type information available to the compiler, therefore the following usage will fail:
+
+```scala mdoc:to-string
+def pathModule(p: Path) = new ModuleDef {
+  make[p.A]
+}
+
+val path1 = new Path
+val path2 = new Path
+```
+
+```scala mdoc:to-string:crash
+Injector()
+  .produceRun(pathModule(path1) ++ pathModule(path2)) {
+    (p1a: path1.A, p2a: path2.A) =>
+      println((p1a, p2a))
+  }
+```
+
+This will fail because while `path1.A` and `p.A` inside `new ModuleDef` are the same type, the varialbes
+`path1` & `p` are spelled differently and this causes a mismatch.
+
+There's one way to workaround this - turn the type member `A` into a type parameter using the [Aux Pattern](http://gigiigig.github.io/posts/2015/09/13/aux-pattern.html),
+and then for that type parameter in turn, summon the type information using `Tag` implicit (as described in @ref[Tagless Final Style chapter](basics.md#tagless-final-style))
+and summon the constructor using the `ClassConstructor` implicit, example:
+
+```scala mdoc:to-string:reset:invisible
+class Path {
+  class A
+}
+```
+
+```scala mdoc:to-string
+import distage.{ClassConstructor, GCMode, ModuleDef, Injector, Tag}
+
+object Path {
+  type Aux[A0] = Path { type A = A0 }
+}
+
+def pathModule[A: Tag: ClassConstructor](p: Path.Aux[A]) = new ModuleDef {
+  make[A]
+}
+
+val path1 = new Path
+val path2 = new Path
+
+Injector()
+  .produceRun(pathModule(path1) ++ pathModule(path2)) {
+    (p1a: path1.A, p2a: path2.A) =>
+      println((p1a, p2a))
+  }
+```
+
+Now the example works, because the `A` inside `pathModule` is `path1.A` & `path2.A` respectively, the same as it is later
+in `produceRun`
+
 ### Depending on Locator
 
 Objects can depend on the outer object graph that contains them (@scaladoc[Locator](izumi.distage.model.Locator)), by including a @scaladoc[LocatorRef](izumi.distage.model.recursive.LocatorRef) parameter:
diff --git a/doc/microsite/src/main/tut/distage/basics.md b/doc/microsite/src/main/tut/distage/basics.md
index 341593c21..7fdae39b3 100644
--- a/doc/microsite/src/main/tut/distage/basics.md
+++ b/doc/microsite/src/main/tut/distage/basics.md
@@ -443,7 +443,7 @@ val io = Injector()
       } yield res1 + res2
   }
 
-new zio.DefaultRuntime{}.unsafeRun(io)
+zio.Runtime.default.unsafeRun(io)
 ```
 
 You need to use effect-aware `Injector.produceF` method to use effect bindings.
@@ -462,9 +462,11 @@ Example:
 ```scala mdoc:reset:to-string
 import distage.{DIKey, ModuleDef, Injector, ProviderMagnet, Tag}
 import izumi.distage.constructors.TraitConstructor
-import zio.console.{Console, putStrLn}
+import zio.console.Console
 import zio.{UIO, URIO, ZIO, Ref, Task}
 
+def putStrLn(s: String): URIO[{ def console: Console.Service }, Unit] = ZIO.accessM(_.console.putStrLn(s))
+
 trait Hello {
   def hello: UIO[String]
 }
@@ -517,7 +519,7 @@ def provideCake[R: TraitConstructor, A: Tag](fn: R => A): ProviderMagnet[A] = {
 val definition = new ModuleDef {
   make[Hello].fromResource(provideCake(makeHello.provide(_)))
   make[World].fromEffect(makeWorld)
-  make[Console.Service[Any]].fromValue(Console.Live.console)
+  make[Console.Service].fromValue(Console.Service.live)
   make[UIO[Unit]].from(provideCake(turboFunctionalHelloWorld.provide))
 }
 
@@ -525,7 +527,7 @@ val main = Injector()
   .produceGetF[Task, UIO[Unit]](definition)
   .useEffect
 
-new zio.DefaultRuntime{}.unsafeRun(main)
+zio.Runtime.global.unsafeRun(main)
 ```
 
 Any ZIO Service that requires an environment can be turned into a service without an environment dependency by providing
diff --git a/doc/microsite/src/main/tut/logstage/00_logstage.md b/doc/microsite/src/main/tut/logstage/00_logstage.md
index eac80c0a4..56d497a17 100644
--- a/doc/microsite/src/main/tut/logstage/00_logstage.md
+++ b/doc/microsite/src/main/tut/logstage/00_logstage.md
@@ -157,12 +157,11 @@ Example:
 
 ```scala mdoc:reset
 import logstage.{IzLogger, LogstageZIO}
-import zio.{IO, DefaultRuntime}
+import zio.IO
 
 val log = LogstageZIO.withFiberId(IzLogger())
 
-val rts = new DefaultRuntime {}
-rts.unsafeRun {
+zio.Runtime.default.unsafeRun {
   log.info(s"Hey! I'm logging with ${log}stage!")
 }
 ```
diff --git a/fundamentals/fundamentals-bio/.jvm/src/main/scala/izumi/functional/bio/BlockingIO3.scala b/fundamentals/fundamentals-bio/.jvm/src/main/scala/izumi/functional/bio/BlockingIO3.scala
index 006652adf..14a643453 100644
--- a/fundamentals/fundamentals-bio/.jvm/src/main/scala/izumi/functional/bio/BlockingIO3.scala
+++ b/fundamentals/fundamentals-bio/.jvm/src/main/scala/izumi/functional/bio/BlockingIO3.scala
@@ -6,7 +6,7 @@ import zio.blocking.Blocking
 import zio.internal.Executor
 import zio.{Has, IO, ZIO}
 
-trait BlockingIO3[F[_, _, _]] extends BlockingIOInstances {
+trait BlockingIO3[F[-_, +_, +_]] extends BlockingIOInstances {
 
   /** Execute a blocking action in `Blocking` thread pool, current task will be safely parked until the blocking task finishes **/
   def shiftBlocking[R, E, A](f: F[R, E ,A]): F[R, E, A]
@@ -24,14 +24,14 @@ trait BlockingIO3[F[_, _, _]] extends BlockingIOInstances {
 }
 
 object BlockingIO3 {
-  def apply[F[_, _, _]: BlockingIO3]: BlockingIO3[F] = implicitly
+  def apply[F[-_, +_, +_]: BlockingIO3]: BlockingIO3[F] = implicitly
 }
 
 private[bio] sealed trait BlockingIOInstances
 object BlockingIOInstances extends LowPriorityBlockingIOInstances {
   // FIXME: bad encoding for lifting to 2-parameters...
-  def BlockingZIOFromThreadPool[R](blockingPool: ThreadPoolExecutor): BlockingIO[ZIO[R, ?, ?]] = {
-    BlockingZIO3FromThreadPool(blockingPool).asInstanceOf[BlockingIO[ZIO[R, ?, ?]]]
+  def BlockingZIOFromThreadPool[R](blockingPool: ThreadPoolExecutor): BlockingIO[ZIO[R, +?, +?]] = {
+    convert3To2(BlockingZIO3FromThreadPool(blockingPool))
   }
 
   def BlockingZIO3FromThreadPool(blockingPool: ThreadPoolExecutor): BlockingIO3[ZIO] = {
@@ -42,11 +42,6 @@ object BlockingIOInstances extends LowPriorityBlockingIOInstances {
     blockingIOZIO3Blocking(Has(blocking))
   }
 
-  // FIXME: bad encoding for lifting to 2-parameters...
-  implicit def blockingIOZIOBlocking[R](implicit blocking: Blocking): BlockingIO[ZIO[R, +?, +?]] = {
-    blockingIOZIO3Blocking(blocking).asInstanceOf[BlockingIO[ZIO[R, +?, +?]]]
-  }
-
   implicit final def blockingIOZIO3Blocking(implicit blocking: Blocking): BlockingIO3[ZIO] = new BlockingIO3[ZIO] {
     val b: Blocking.Service = blocking.get
     override def shiftBlocking[R, E, A](f: ZIO[R, E ,A]): ZIO[R, E, A] = b.blocking(f)
@@ -55,14 +50,18 @@ object BlockingIOInstances extends LowPriorityBlockingIOInstances {
   }
 }
 
-trait LowPriorityBlockingIOInstances {
-  type ZIOBlocking = { type l[-R, +E, +A] = ZIO[R with Blocking, E, A] }
+sealed trait LowPriorityBlockingIOInstances extends LowPriorityBlockingIOInstances1 {
+  type ZIOWithBlocking[-R, +E, +A] = ZIO[R with Blocking, E, A]
 
-  implicit def blockingIOZIOR[R]: BlockingIO[ZIO[R with Blocking, +?, +?]] = blockingIOZIO3R.asInstanceOf[BlockingIO[ZIO[R with Blocking, +?, +?]]]
+  @inline implicit final def blockingIOZIOR[R]: BlockingIO[ZIOWithBlocking[R, +?, +?]] = convert3To2[BlockingIO3, ZIOWithBlocking, R](blockingIOZIO3R)
 
-  implicit final val blockingIOZIO3R: BlockingIO3[ZIOBlocking#l] = new BlockingIO3[ZIOBlocking#l] {
+  implicit final val blockingIOZIO3R: BlockingIO3[ZIOWithBlocking] = new BlockingIO3[ZIOWithBlocking] {
     override def shiftBlocking[R, E, A](f: ZIO[R with Blocking, E, A]): ZIO[R with Blocking, E, A] = zio.blocking.blocking(f)
     override def syncBlocking[A](f: => A): ZIO[Blocking, Throwable, A] = zio.blocking.effectBlocking(f)
     override def syncInterruptibleBlocking[A](f: => A): ZIO[Blocking, Throwable, A] = zio.blocking.effectBlockingInterrupt(f)
   }
 }
+
+sealed trait LowPriorityBlockingIOInstances1 {
+  @inline implicit final def blockingIO3To2[FR[-_, +_, +_], R](implicit BlockingIO3: BlockingIO3[FR]): BlockingIO[FR[R, +?, +?]] = convert3To2(BlockingIO3)
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOSyntax.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOSyntax.scala
index 74533f46d..022541707 100644
--- a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOSyntax.scala
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOSyntax.scala
@@ -221,7 +221,7 @@ object BIOSyntax {
     @inline final def BIOBifunctor[F[+_, +_]: BIOBifunctor]: BIOBifunctor[F] = implicitly
   }
   trait BIOImplicitPuns11 {
-    @inline implicit final def BIOFunctor[F[_, + _] : BIOFunctor, E, A](self: F[E, A]): BIOSyntax.BIOFunctorOps[F, E, A] = new BIOSyntax.BIOFunctorOps[F, E, A](self)
+    @inline implicit final def BIOFunctor[F[_, + _]: BIOFunctor, E, A](self: F[E, A]): BIOSyntax.BIOFunctorOps[F, E, A] = new BIOSyntax.BIOFunctorOps[F, E, A](self)
     @inline final def BIOFunctor[F[_, +_]: BIOFunctor]: BIOFunctor[F] = implicitly
   }
 
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/BIOZio.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/BIOZio.scala
index 3f99874da..d71babbbd 100644
--- a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/BIOZio.scala
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/BIOZio.scala
@@ -6,7 +6,7 @@ import izumi.functional.bio.BIOExit.ZIOExit
 import izumi.functional.bio.{BIOAsync, BIOExit, BIOFiber, BIOTemporal, __PlatformSpecific}
 import zio.ZIO.ZIOWithFilterOps
 import zio.clock.Clock
-import zio.compatrc18.zio_succeed_Now.succeedNow
+import zio.internal.ZIOSucceedNow
 import zio.duration.Duration.fromScala
 import zio.{Schedule, ZIO}
 
@@ -19,7 +19,7 @@ object BIOZio extends BIOZio[Any]
 class BIOZio[R] extends BIOAsync[ZIO[R, +?, +?]] {
   private[this] final type IO[+E, +A] = ZIO[R, E, A]
 
-  @inline override final def pure[A](a: A): IO[Nothing, A] = succeedNow(a)
+  @inline override final def pure[A](a: A): IO[Nothing, A] = ZIOSucceedNow(a)
   @inline override final def sync[A](effect: => A): IO[Nothing, A] = ZIO.effectTotal(effect)
   @inline override final def syncThrowable[A](effect: => A): IO[Throwable, A] = ZIO.effect(effect)
   @inline override final def suspend[A](effect: => IO[Throwable, A]): IO[Throwable, A] = ZIO.effectSuspend(effect)
@@ -82,23 +82,23 @@ class BIOZio[R] extends BIOAsync[ZIO[R, +?, +?]] {
 
   @inline override final def racePair[E, A, B](r1: IO[E, A], r2: IO[E, B]): IO[E, Either[(A, BIOFiber[ZIO[R, +?, +?], E, B]), (BIOFiber[ZIO[R, +?, +?], E, A], B)]] = {
     (r1.interruptible raceWith r2.interruptible)(
-      { case (l, f) => l.fold(f.interrupt *> ZIO.halt(_), succeedNow).map(lv => Left((lv, BIOFiber.fromZIO(f)))) },
-      { case (r, f) => r.fold(f.interrupt *> ZIO.halt(_), succeedNow).map(rv => Right((BIOFiber.fromZIO(f), rv))) }
+      { case (l, f) => l.fold(f.interrupt *> ZIO.halt(_), ZIOSucceedNow).map(lv => Left((lv, BIOFiber.fromZIO(f)))) },
+      { case (r, f) => r.fold(f.interrupt *> ZIO.halt(_), ZIOSucceedNow).map(rv => Right((BIOFiber.fromZIO(f), rv))) }
     )
   }
 
   @inline override final def async[E, A](register: (Either[E, A] => Unit) => Unit): IO[E, A] = {
-    ZIO.effectAsync(cb => register(cb apply _.fold(ZIO.fail(_), succeedNow)))
+    ZIO.effectAsync(cb => register(cb apply _.fold(ZIO.fail(_), ZIOSucceedNow)))
   }
 
   @inline override final def asyncF[E, A](register: (Either[E, A] => Unit) => ZIO[R, E, Unit]): ZIO[R, E, A] = {
-    ZIO.effectAsyncM(cb => register(cb apply _.fold(ZIO.fail(_), succeedNow)))
+    ZIO.effectAsyncM(cb => register(cb apply _.fold(ZIO.fail(_), ZIOSucceedNow)))
   }
 
   @inline override final def asyncCancelable[E, A](register: (Either[E, A] => Unit) => Canceler): IO[E, A] = {
     ZIO.effectAsyncInterrupt[R, E, A] {
       cb =>
-        val canceler = register(cb apply _.fold(ZIO.fail(_), succeedNow))
+        val canceler = register(cb apply _.fold(ZIO.fail(_), ZIOSucceedNow))
         Left(canceler)
     }
   }
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/package.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/package.scala
index 3b7fa1973..d99dfaf22 100644
--- a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/package.scala
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/package.scala
@@ -275,11 +275,8 @@ package object bio extends BIOSyntax {
   }
 
   private[bio] sealed trait BIOForkInstances
-  object BIOForkInstances {
-    // FIXME: bad encoding for lifting to 2-parameters...
-    implicit def BIOForkZioIO[R]: BIOFork[ZIO[R, +?, +?]] = BIOForkZio.asInstanceOf[BIOFork[ZIO[R, +?, +?]]]
-
-    implicit object BIOForkZio extends BIOFork3[ZIO] {
+  object BIOForkInstances extends LowPriorityBIOForkInstances {
+    implicit val BIOForkZio: BIOFork3[ZIO] = new BIOFork3[ZIO] {
       override def fork[R, E, A](f: ZIO[R, E, A]): ZIO[R, Nothing, BIOFiber[ZIO[Any, +?, +?], E, A]] =
         f
           // FIXME: ZIO Bug / feature (interruption inheritance) breaks behavior in bracket/DIResource
@@ -290,13 +287,16 @@ package object bio extends BIOSyntax {
           .map(BIOFiber.fromZIO)
     }
   }
+  sealed trait LowPriorityBIOForkInstances {
+    @inline implicit final def BIOFork3To2[FR[-_, +_, +_], R](implicit BIOFork3: BIOFork3[FR]): BIOFork[FR[R, +?, +?]] = convert3To2(BIOFork3)
+  }
 
   type BIOLatch[F[+_, +_]] = BIOPromise[F, Nothing, Unit]
 
   type BIOFork[F[+_, +_]] = BIOFork3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]]]
-  type BlockingIO[F[_, _]] = BlockingIO3[Lambda[(R, E, A) => F[E, A]]]
+  type BlockingIO[F[+_, +_]] = BlockingIO3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]]]
   object BlockingIO {
-    def apply[F[_, _]: BlockingIO]: BlockingIO[F] = implicitly
+    def apply[F[+_, +_]: BlockingIO]: BlockingIO[F] = implicitly
   }
 
   type BIOPrimitives3[F[-_, +_, +_]] = BIOPrimitives[F[Any, +?, +?]]
@@ -316,4 +316,8 @@ package object bio extends BIOSyntax {
     def apply[F[_, _]: Entropy2]: Entropy2[F] = implicitly
   }
 
+  @inline private[bio] final def convert3To2[C[_[-_, +_, +_]], FR[-_, +_, +_], R](instance: C[FR]): C[Lambda[(`-R0`, `+E`, `+A`) => FR[R, E, A]]] = {
+    instance.asInstanceOf[C[Lambda[(`-R0`, `+E`, `+A`) => FR[R, E, A]]]]
+  }
+
 }
diff --git a/fundamentals/fundamentals-bio/src/main/scala/zio/clock/compatrc18/zio_Clock_Live.scala b/fundamentals/fundamentals-bio/src/main/scala/zio/clock/compatrc18/zio_Clock_Live.scala
deleted file mode 100644
index a30ed4b62..000000000
--- a/fundamentals/fundamentals-bio/src/main/scala/zio/clock/compatrc18/zio_Clock_Live.scala
+++ /dev/null
@@ -1,32 +0,0 @@
-package zio.clock.compatrc18
-
-import java.time.{Instant, OffsetDateTime, ZoneId}
-import java.util.concurrent.TimeUnit
-
-import zio.clock.Clock
-import zio.duration.Duration
-import zio.{Has, IO, UIO, ZIO}
-
-// workaround for missing static Clock.Live
-object zio_Clock_Live extends Clock.Service {
-  def currentTime(unit: TimeUnit): UIO[Long] = {
-    IO.effectTotal(System.currentTimeMillis).map(l => unit.convert(l, TimeUnit.MILLISECONDS))
-  }
-  val nanoTime: UIO[Long] = IO.effectTotal(System.nanoTime)
-
-  def sleep(duration: Duration): UIO[Unit] = {
-    UIO.effectAsyncInterrupt {
-      cb =>
-        val canceler = zio.clock.Clock.globalScheduler.schedule(() => cb(UIO.unit), duration)
-        Left(UIO.effectTotal(canceler()))
-    }
-  }
-  def currentDateTime: ZIO[Any, Nothing, OffsetDateTime] = {
-    for {
-      millis <- currentTime(TimeUnit.MILLISECONDS)
-      zone <- ZIO.effectTotal(ZoneId.systemDefault)
-    } yield OffsetDateTime.ofInstant(Instant.ofEpochMilli(millis), zone)
-  }
-
-  val live: Has[Clock.Service] = Has(this)
-}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/zio/compatrc18/zio_succeed_Now.scala b/fundamentals/fundamentals-bio/src/main/scala/zio/compatrc18/zio_succeed_Now.scala
deleted file mode 100644
index e15a83b85..000000000
--- a/fundamentals/fundamentals-bio/src/main/scala/zio/compatrc18/zio_succeed_Now.scala
+++ /dev/null
@@ -1,5 +0,0 @@
-package zio.compatrc18
-
-object zio_succeed_Now {
-  @inline def succeedNow[A](a: A): zio.ZIO[Any, Nothing, A] = new zio.ZIO.Succeed[A](a)
-}
diff --git a/fundamentals/fundamentals-json-circe/src/main/scala/izumi/fundamentals/json/circe/IRTWithCirce.scala b/fundamentals/fundamentals-json-circe/src/main/scala/izumi/fundamentals/json/circe/IRTWithCirce.scala
new file mode 100644
index 000000000..4339e1548
--- /dev/null
+++ b/fundamentals/fundamentals-json-circe/src/main/scala/izumi/fundamentals/json/circe/IRTWithCirce.scala
@@ -0,0 +1,85 @@
+package izumi.fundamentals.json.circe
+
+import io.circe.{Codec, Decoder, Encoder, derivation}
+
+import scala.language.experimental.macros
+import scala.reflect.macros.blackbox
+
+/**
+  * Provides circe codecs for case classes and sealed traits
+  *
+  * {{{
+  *   final case class Abc(a: String, b: String, c: String)
+  *
+  *   object Abc extends WithCirce[Abc]
+  * }}}
+  *
+  * To derive codecs for a sealed trait with branches inside its
+  * own companion object, use a proxy object - this works around
+  * a scala limitation: https://github.com/milessabin/shapeless/issues/837
+  *
+  * {{{
+  *   sealed trait Abc
+  *
+  *   private abcCodecs extends WithCirce[Abc]
+  *
+  *   object Abc extends WithCirce(abcCodecs) {
+  *     final case class A()
+  *     object A extends WithCirce[A]
+  *
+  *     final case class B()
+  *     object B extends WithCirce[B]
+  *     final case class C()
+  *
+  *     object C extends WithCirce[C]
+  *   }
+  * }}}
+  *
+  */
+abstract class WithCirce[A]()(implicit derivedCodec: DerivationDerivedCodec[A]) {
+  // workaround for https://github.com/milessabin/shapeless/issues/837
+  def this(proxy: WithCirce[A]) = this()(DerivationDerivedCodec(proxy.codec))
+
+  implicit val codec: Codec.AsObject[A] = derivedCodec.value
+}
+
+// TODO: merge upstream, also with @JsonCodec
+final class MaterializeDerivationMacros(override val c: blackbox.Context) extends derivation.DerivationMacros(c) {
+  import c.universe._
+
+  def materializeEncoderImpl[A: c.WeakTypeTag]: c.Expr[DerivationDerivedEncoder[A]] =
+    c.Expr[DerivationDerivedEncoder[A]] {
+      q"""{
+           new ${weakTypeOf[DerivationDerivedEncoder[A]]}(_root_.io.circe.derivation.deriveEncoder[${weakTypeOf[A]}])
+         }"""
+    }
+
+  def materializeDecoderImpl[A: c.WeakTypeTag]: c.Expr[DerivationDerivedDecoder[A]] =
+    c.Expr[DerivationDerivedDecoder[A]] {
+      q"""{
+           new ${weakTypeOf[DerivationDerivedDecoder[A]]}(_root_.io.circe.derivation.deriveDecoder[${weakTypeOf[A]}])
+         }"""
+    }
+
+  def materializeCodecImpl[A: c.WeakTypeTag]: c.Expr[DerivationDerivedCodec[A]] =
+    c.Expr[DerivationDerivedCodec[A]] {
+      q"""{
+           new ${weakTypeOf[DerivationDerivedCodec[A]]}(_root_.io.circe.derivation.deriveCodec[${weakTypeOf[A]}])
+         }"""
+    }
+}
+
+final case class DerivationDerivedEncoder[A](value: Encoder.AsObject[A]) extends AnyVal
+object DerivationDerivedEncoder {
+  implicit def materialize[A]: DerivationDerivedEncoder[A] = macro MaterializeDerivationMacros.materializeEncoderImpl[A]
+}
+
+final case class DerivationDerivedDecoder[A](value: Decoder[A]) extends AnyVal
+object DerivationDerivedDecoder {
+  implicit def materialize[A]: DerivationDerivedDecoder[A] = macro MaterializeDerivationMacros.materializeDecoderImpl[A]
+}
+
+final case class DerivationDerivedCodec[A](value: Codec.AsObject[A]) extends AnyVal
+object DerivationDerivedCodec {
+  implicit def materialize[A]: DerivationDerivedCodec[A] = macro MaterializeDerivationMacros.materializeCodecImpl[A]
+}
diff --git a/fundamentals/fundamentals-reflection/src/main/scala/izumi/fundamentals/reflection/macrortti/LightTypeTag.scala b/fundamentals/fundamentals-reflection/src/main/scala/izumi/fundamentals/reflection/macrortti/LightTypeTag.scala
index 414b51df1..8a294319e 100644
--- a/fundamentals/fundamentals-reflection/src/main/scala/izumi/fundamentals/reflection/macrortti/LightTypeTag.scala
+++ b/fundamentals/fundamentals-reflection/src/main/scala/izumi/fundamentals/reflection/macrortti/LightTypeTag.scala
@@ -195,7 +195,7 @@ object LightTypeTag {
   }
 
   def parse[T](hashCode: Int, refString: String, basesString: String, @unused version: Int): LightTypeTag = {
-    lazy val shared = {
+    lazy val shared: SubtypeDBs = {
       subtypeDBsSerializer.unpickle(ByteBuffer.wrap(basesString.getBytes(StandardCharsets.ISO_8859_1)))
     }
 
diff --git a/fundamentals/fundamentals-reflection/src/main/scala/izumi/fundamentals/reflection/macrortti/LightTypeTagImpl.scala b/fundamentals/fundamentals-reflection/src/main/scala/izumi/fundamentals/reflection/macrortti/LightTypeTagImpl.scala
index 0c9ae4560..c51b67503 100644
--- a/fundamentals/fundamentals-reflection/src/main/scala/izumi/fundamentals/reflection/macrortti/LightTypeTagImpl.scala
+++ b/fundamentals/fundamentals-reflection/src/main/scala/izumi/fundamentals/reflection/macrortti/LightTypeTagImpl.scala
@@ -3,11 +3,11 @@ package izumi.fundamentals.reflection.macrortti
 import izumi.fundamentals.collections.IzCollections._
 import izumi.fundamentals.platform.console.TrivialLogger
 import izumi.fundamentals.platform.strings.IzString._
+import izumi.fundamentals.reflection.DebugProperties
 import izumi.fundamentals.reflection.macrortti.LightTypeTagImpl.{Broken, globalCache}
 import izumi.fundamentals.reflection.macrortti.LightTypeTagRef.RefinementDecl.TypeMember
 import izumi.fundamentals.reflection.macrortti.LightTypeTagRef.SymName.{SymLiteral, SymTermName, SymTypeName}
 import izumi.fundamentals.reflection.macrortti.LightTypeTagRef._
-import izumi.fundamentals.reflection.{DebugProperties, SingletonUniverse}
 
 import scala.annotation.tailrec
 import scala.collection.mutable
diff --git a/project/Deps.sc b/project/Deps.sc
index b85866247..d0804374d 100644
--- a/project/Deps.sc
+++ b/project/Deps.sc
@@ -17,6 +17,7 @@ object Izumi {
     val circe_generic_extras = Version.VExpr("V.circe_generic_extras")
     val circe_derivation = Version.VExpr("V.circe_derivation")
     val pureconfig = Version.VExpr("V.pureconfig")
+    val magnolia = Version.VExpr("V.magnolia")
     val jawn = Version.VExpr("V.jawn")
     val http4s = Version.VExpr("V.http4s")
     val classgraph = Version.VExpr("V.classgraph")
@@ -24,6 +25,7 @@ object Izumi {
     val typesafe_config = Version.VExpr("V.typesafe_config")
     val cglib_nodep = Version.VExpr("V.cglib_nodep")
     val scala_java_time = Version.VExpr("V.scala_java_time")
+    val scalamock = Version.VExpr("V.scalamock")
     val docker_java = Version.VExpr("V.docker_java")
   }
 
@@ -77,6 +79,7 @@ object Izumi {
       circe_derivation,
     ).map(_ in Scope.Compile.all)
     final val pureconfig_magnolia = Library("com.github.pureconfig", "pureconfig-magnolia", V.pureconfig, LibraryType.Auto)
+    final val magnolia = Library("com.propensive", "magnolia", V.magnolia, LibraryType.Auto)
 
     final val zio_core = Library("dev.zio", "zio", V.zio, LibraryType.Auto)
     final val zio_interop_cats = Library("dev.zio", "zio-interop-cats", V.zio_interop_cats, LibraryType.Auto)
@@ -104,6 +107,7 @@ object Izumi {
 
     final val fast_classpath_scanner = Library("io.github.classgraph", "classgraph", V.classgraph, LibraryType.Invariant) in Scope.Compile.jvm
     final val scala_java_time = Library("io.github.cquiroz", "scala-java-time", V.scala_java_time, LibraryType.Auto) in Scope.Compile.js
+    final val scalamock = Library("org.scalamock", "scalamock", V.scalamock, LibraryType.Auto)
 
     final val slf4j_api = Library("org.slf4j", "slf4j-api", V.slf4j, LibraryType.Invariant) in Scope.Compile.jvm
     final val slf4j_simple = Library("org.slf4j", "slf4j-simple", V.slf4j, LibraryType.Invariant) in Scope.Test.jvm
@@ -401,7 +405,10 @@ object Izumi {
       ),
       Artifact(
         name = Projects.fundamentals.fundamentalsJsonCirce,
-        libs = circe ++ Seq(jawn in Scope.Compile.js),
+        libs = circe ++ Seq(
+          jawn in Scope.Compile.js,
+          scala_reflect in Scope.Provided.all,
+        ),
         depends = Projects.fundamentals.basics,
         platforms = Targets.cross,
       ),
@@ -439,7 +446,7 @@ object Izumi {
       ),
       Artifact(
         name = Projects.distage.config,
-        libs = Seq(pureconfig_magnolia).map(_ in Scope.Compile.all) ++ Seq(scala_reflect in Scope.Provided.all),
+        libs = Seq(pureconfig_magnolia, magnolia).map(_ in Scope.Compile.all) ++ Seq(scala_reflect in Scope.Provided.all),
         depends = Seq(Projects.distage.model).map(_ in Scope.Compile.all) ++
           Seq(Projects.distage.core).map(_ tin Scope.Test.all),
         platforms = Targets.jvm,
@@ -489,7 +496,10 @@ object Izumi {
       ),
       Artifact(
         name = Projects.distage.testkitScalatest,
-        libs = allMonadsOptional ++ Seq(scalatest.dependency).map(_ in Scope.Compile.all),
+        libs = allMonadsOptional ++ Seq(
+          scalamock in Scope.Test.all,
+          scalatest.dependency in Scope.Compile.all,
+        ),
         depends =
           Seq(Projects.distage.testkitCore).map(_ in Scope.Compile.all) ++
             Seq(Projects.distage.core, Projects.distage.plugins).map(_ tin Scope.Compile.all),
diff --git a/project/Versions.scala b/project/Versions.scala
index 722c0052e..7fda01af7 100644
--- a/project/Versions.scala
+++ b/project/Versions.scala
@@ -9,17 +9,22 @@ object V {
 
   val cats = "2.1.1"
   val cats_effect = "2.1.2"
-  val zio = "1.0.0-RC18-1"
+  val zio = "1.0.0-RC18-2"
   val zio_interop_cats = "2.0.0.0-RC11"
 
   val circe = "0.13.0"
   val circe_generic_extras = "0.13.0"
   val circe_derivation = "0.13.0-M2"
   val pureconfig = "0.12.3"
+  val magnolia = "0.12.8"
   val jawn = "1.0.0"
 
   val http4s = "0.21.1"
 
+  // good to drop - scala
+  val scala_java_time = "2.0.0-RC3"
+  val scalamock = "4.4.0"
+
   // java-only dependencies below
   val classgraph = "4.8.65"
   val slf4j = "1.7.30"
@@ -27,6 +32,5 @@ object V {
 
   // good to drop - java
   val cglib_nodep = "3.3.0"
-  val scala_java_time = "2.0.0-RC3"
-  val docker_java = "3.2.0"
+  val docker_java = "3.2.1"
 }
diff --git a/project/project/PluginVersions.scala b/project/project/PluginVersions.scala
index 4792f5b9a..607045462 100644
--- a/project/project/PluginVersions.scala
+++ b/project/project/PluginVersions.scala
@@ -1,5 +1,5 @@
 object PV {
-  val sbt_mdoc = "2.1.1"
+  val sbt_mdoc = "2.1.4"
   val sbt_paradox_material_theme = "0.6.0"
   val sbt_ghpages = "0.6.3"
   val sbt_site = "1.3.3"


Test patch:
diff --git a/distage/distage-core-api/src/test/scala/izumi/SafeTypeTest.scala b/distage/distage-core-api/src/test/scala/izumi/SafeTypeTest.scala
index bee69194b..66a35fe12 100644
--- a/distage/distage-core-api/src/test/scala/izumi/SafeTypeTest.scala
+++ b/distage/distage-core-api/src/test/scala/izumi/SafeTypeTest.scala
@@ -1,6 +1,6 @@
 package izumi
 
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
+import izumi.distage.model.reflection._
 import izumi.fundamentals.reflection.Tags.{Tag, TagK}
 import org.scalatest.wordspec.AnyWordSpec
 
diff --git a/distage/distage-core/src/test/scala/izumi/distage/dsl/DSLTest.scala b/distage/distage-core/src/test/scala/izumi/distage/dsl/DSLTest.scala
index 4fd41eeb3..9b1659707 100644
--- a/distage/distage-core/src/test/scala/izumi/distage/dsl/DSLTest.scala
+++ b/distage/distage-core/src/test/scala/izumi/distage/dsl/DSLTest.scala
@@ -382,7 +382,7 @@ class DSLTest extends AnyWordSpec with MkInjector {
             ImplDef.ResourceImpl(
               SafeType.get[ImplXYZ],
               SafeType.getK[Identity],
-              ImplDef.ProviderImpl(SafeType.get[X], ClassConstructor[X].provider.get),
+              ImplDef.ProviderImpl(SafeType.get[X], ClassConstructor[X].get),
             ),
             Set.empty,
             SourceFilePosition.unknown
diff --git a/distage/distage-core/src/test/scala/izumi/distage/impl/ProviderMagnetTest.scala b/distage/distage-core/src/test/scala/izumi/distage/impl/ProviderMagnetTest.scala
index ed136ab76..1d10232d7 100644
--- a/distage/distage-core/src/test/scala/izumi/distage/impl/ProviderMagnetTest.scala
+++ b/distage/distage-core/src/test/scala/izumi/distage/impl/ProviderMagnetTest.scala
@@ -4,10 +4,11 @@ import distage._
 import izumi.distage.fixtures.BasicCases.BasicCase4.ClassTypeAnnT
 import izumi.distage.fixtures.ProviderCases.ProviderCase1
 import izumi.distage.model.providers.ProviderMagnet
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.TypedRef
+import izumi.distage.model.reflection.TypedRef
 import izumi.fundamentals.platform.build.ProjectAttributeMacro
 import izumi.fundamentals.platform.language.IzScala.ScalaRelease
 import izumi.fundamentals.platform.language.Quirks._
+import org.scalatest.exceptions.TestFailedException
 import org.scalatest.wordspec.AnyWordSpec
 
 class ProviderMagnetTest extends AnyWordSpec {
@@ -345,11 +346,24 @@ class ProviderMagnetTest extends AnyWordSpec {
       assert(p1 == p2)
     }
 
-    "progression test: FAILS to handle case class .apply references with argument annotations" in {
-      val fn = ProviderMagnet.apply(ClassArgAnn.apply _).get
+    "should be unequal after .map" in {
+      val p1 = ClassConstructor[Some[Int]]
+      val p2 = p1.map(identity)
+      val p3 = p2.map(identity)
+
+      assert(p1 != p2)
+      assert(p2 != p3)
+    }
+
+    "should be unequal after .addUnused" in {
+      val p1 = ClassConstructor[Some[Int]]
+      val p2 = p1.addDependency[Int]
+      val p3 = p2.addDependency[String]
+      val p4 = p3.addDependency[Unit]
 
-      assert(!fn.diKeys.contains(DIKey.get[String].named("classargann1")))
-      assert(!fn.diKeys.contains(DIKey.get[Int].named("classargann2")))
+      assert(p1 != p2)
+      assert(p2 != p3)
+      assert(p3 != p4)
     }
 
     "fail on multiple conflicting annotations on the same parameter" in {
@@ -357,8 +371,21 @@ class ProviderMagnetTest extends AnyWordSpec {
       assertTypeError("ProviderMagnet.apply(defconfannfn2 _)")
     }
 
+    "progression test: Can't handle case class .apply references with argument annotations" in {
+      val fn = ProviderMagnet.apply(ClassArgAnn.apply _).get
+
+      intercept[TestFailedException] {
+        assert(fn.diKeys.contains(DIKey.get[String].named("classargann1")))
+      }
+      intercept[TestFailedException] {
+        assert(fn.diKeys.contains(DIKey.get[Int].named("classargann2")))
+      }
+    }
+
     "progression test: Can't expand functions with implicit arguments" in {
-      assertTypeError("ProviderMagnet.apply(defimplicitfn _)")
+      intercept[TestFailedException] {
+        assertCompiles("ProviderMagnet.apply(defimplicitfn _)")
+      }
     }
   }
 
diff --git a/distage/distage-core/src/test/scala/izumi/distage/injector/HigherKindsTest.scala b/distage/distage-core/src/test/scala/izumi/distage/injector/HigherKindsTest.scala
index 67102b583..d1a729f81 100644
--- a/distage/distage-core/src/test/scala/izumi/distage/injector/HigherKindsTest.scala
+++ b/distage/distage-core/src/test/scala/izumi/distage/injector/HigherKindsTest.scala
@@ -11,7 +11,7 @@ class HigherKindsTest extends AnyWordSpec with MkInjector {
   "support tagless final style module definitions" in {
     import HigherKindsCase1._
 
-    case class Definition[F[_] : TagK : Pointed](getResult: Int) extends ModuleDef {
+    case class Definition[F[_]: TagK : Pointed](getResult: Int) extends ModuleDef {
       // TODO: hmmm, what to do with this
       addImplicit[Pointed[F]]
 
diff --git a/distage/distage-core/src/test/scala/izumi/distage/staticinjector/MacroAutoTraitsTest.scala b/distage/distage-core/src/test/scala/izumi/distage/staticinjector/MacroAutoTraitsTest.scala
index 4939000b6..b37b194a4 100644
--- a/distage/distage-core/src/test/scala/izumi/distage/staticinjector/MacroAutoTraitsTest.scala
+++ b/distage/distage-core/src/test/scala/izumi/distage/staticinjector/MacroAutoTraitsTest.scala
@@ -6,13 +6,13 @@ import izumi.distage.fixtures.TypesCases.TypesCase3
 import izumi.distage.injector.MkInjector
 import izumi.distage.model.PlannerInput
 import izumi.distage.model.definition.ModuleDef
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse.TypedRef
+import izumi.distage.model.reflection.TypedRef
 import org.scalatest.wordspec.AnyWordSpec
 
 class MacroAutoTraitsTest extends AnyWordSpec with MkInjector {
 
   "construct a basic trait" in {
-    val traitCtor = AnyConstructor[Aaa].provider.get
+    val traitCtor = AnyConstructor[Aaa].get
 
     val value = traitCtor.unsafeApply(Seq(TypedRef.byName(5), TypedRef.byName(false))).asInstanceOf[Aaa]
 
diff --git a/distage/distage-extension-config/src/test/resources/private-fields-test.conf b/distage/distage-extension-config/src/test/resources/private-fields-test.conf
new file mode 100644
index 000000000..dbfae791d
--- /dev/null
+++ b/distage/distage-extension-config/src/test/resources/private-fields-test.conf
@@ -0,0 +1,3 @@
+PrivateCaseClass {
+  private-custom-field-name = super secret value
+}
diff --git a/distage/distage-extension-config/src/test/scala/com/github/pshirshov/configapp/TestConfigReaders.scala b/distage/distage-extension-config/src/test/scala/com/github/pshirshov/configapp/TestConfigReaders.scala
index 0732b7c58..978d59c87 100644
--- a/distage/distage-extension-config/src/test/scala/com/github/pshirshov/configapp/TestConfigReaders.scala
+++ b/distage/distage-extension-config/src/test/scala/com/github/pshirshov/configapp/TestConfigReaders.scala
@@ -25,6 +25,12 @@ case class CustomCaseClass(
                             mapListCustomObject: Map[String, List[CustomObject]],
                           )
 
+case class PrivateCaseClass(
+                             private val `private-custom-field-name`: String
+                           ) {
+  val customFieldName = `private-custom-field-name`
+}
+
 case class CustomObject(value: Int)
 object CustomObject {
   implicit val pureconfigReader: ConfigReader[CustomObject] = ConfigReader.fromStringOpt {
@@ -84,4 +90,9 @@ object TestConfigReaders {
     make[Service[CustomCaseClass]]
     makeConfig[CustomCaseClass]("CustomCaseClass")
   })
+
+  final val privateFieldsCodecDefinition = PlannerInput.noGc(new ConfigModuleDef {
+    make[Service[PrivateCaseClass]]
+    makeConfig[PrivateCaseClass]("PrivateCaseClass")
+  })
 }
diff --git a/distage/distage-extension-config/src/test/scala/izumi/distage/config/ConfigTest.scala b/distage/distage-extension-config/src/test/scala/izumi/distage/config/ConfigTest.scala
index 175881931..b23fad7de 100644
--- a/distage/distage-extension-config/src/test/scala/izumi/distage/config/ConfigTest.scala
+++ b/distage/distage-extension-config/src/test/scala/izumi/distage/config/ConfigTest.scala
@@ -14,7 +14,8 @@ import scala.collection.immutable.ListSet
 
 final class ConfigTest extends AnyWordSpec {
   def mkConfigModule(path: String)(p: PlannerInput): PlannerInput = {
-    p.copy(bindings = p.bindings ++ mkModule(ConfigFactory.load(path)))
+    p.copy(bindings = p.bindings ++
+      mkModule(ConfigFactory.load(path, ConfigParseOptions.defaults().setAllowMissing(false), ConfigResolveOptions.noSystem())))
   }
 
   def mkModule(config: Config): AppConfigModule = {
@@ -148,6 +149,13 @@ final class ConfigTest extends AnyWordSpec {
       assert(context.get[Service[BackticksCaseClass]].conf == BackticksCaseClass(true))
     }
 
+    "resolve case classes with private fields" in {
+      val context = Injector()
+        .produce(mkConfigModule("private-fields-test.conf")(TestConfigReaders.privateFieldsCodecDefinition)).unsafeGet()
+
+      assert(context.get[Service[PrivateCaseClass]].conf == PrivateCaseClass("super secret value"))
+    }
+
     "resolve config sealed traits (with progression test for https://github.com/scala/bug/issues/11645)" in {
       // FIXME: pureconfig-magnolia can't read enumerations properly
       val context1 =
diff --git a/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/DistageTestDockerBIO.scala b/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/DistageTestDockerBIO.scala
index 861d324ba..d205206a9 100644
--- a/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/DistageTestDockerBIO.scala
+++ b/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/DistageTestDockerBIO.scala
@@ -15,14 +15,14 @@ final class DistageTestDockerBIO extends DistageBIOSpecScalatest[IO] {
       "support docker resources" in {
         service: PgSvcExample =>
           for {
-            _ <- IO(println(s"ports/1: pg=${service.pg} ddb=${service.ddb} "))
+            _ <- IO(println(s"ports/1: pg=${service.pg} ddb=${service.ddb} kafka=${service.kafka} cs=${service.cs}"))
           } yield ()
       }
 
       "support memoization" in {
         service: PgSvcExample =>
           for {
-            _ <- IO(println(s"ports/2: pg=${service.pg} ddb=${service.ddb} "))
+            _ <- IO(println(s"ports/2: pg=${service.pg} ddb=${service.ddb} kafka=${service.kafka} cs=${service.cs}"))
           } yield ()
       }
     }
diff --git a/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/fixtures/DockerPlugin.scala b/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/fixtures/DockerPlugin.scala
index 60712a206..cad54024a 100644
--- a/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/fixtures/DockerPlugin.scala
+++ b/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/fixtures/DockerPlugin.scala
@@ -1,39 +1,52 @@
 package izumi.distage.testkit.docker.fixtures
 
 import distage.config.ConfigModuleDef
-import izumi.distage.model.definition.Id
-import izumi.distage.model.definition.StandardAxis.Env
-import izumi.distage.effect.modules.{CatsDIEffectModule, ZIODIEffectModule}
-import izumi.distage.plugins.PluginDef
 import izumi.distage.docker.Docker.AvailablePort
-import izumi.distage.docker.examples.{DynamoDocker, PostgresDocker}
+import izumi.distage.docker.examples._
 import izumi.distage.docker.modules.DockerContainerModule
+import izumi.distage.effect.modules.{CatsDIEffectModule, ZIODIEffectModule}
 import izumi.distage.framework.model.IntegrationCheck
+import izumi.distage.model.definition.Id
+import izumi.distage.model.definition.StandardAxis.Env
+import izumi.distage.plugins.PluginDef
 import izumi.fundamentals.platform.integration.{PortCheck, ResourceCheck}
 import zio.Task
 
 class PgSvcExample(
-                    val pg: AvailablePort @Id("pg"),
-                    val ddb: AvailablePort @Id("ddb"),
-                  ) extends IntegrationCheck {
+  val pg: AvailablePort @Id("pg"),
+  val ddb: AvailablePort @Id("ddb"),
+  val kafka: AvailablePort @Id("kafka"),
+  val cs: AvailablePort @Id("cs"),
+) extends IntegrationCheck {
   override def resourcesAvailable(): ResourceCheck = {
     new PortCheck(10).checkPort(pg.hostV4, pg.port)
   }
 }
 
-object MonadPlugin extends PluginDef
-  with CatsDIEffectModule
-  with ZIODIEffectModule
+object MonadPlugin extends PluginDef with CatsDIEffectModule with ZIODIEffectModule
 
 object DockerPlugin extends DockerContainerModule[Task] with PluginDef {
   make[DynamoDocker.Container].fromResource {
     DynamoDocker.make[Task]
   }
 
+  include(new CassandraDockerModule[Task])
+  include(new ZookeeperDockerModule[Task])
+  include(new KafkaDockerModule[Task])
+
+  make[AvailablePort].named("cs").tagged(Env.Test).from {
+    cs: CassandraDocker.Container =>
+      cs.availablePorts(CassandraDocker.primaryPort).head
+  }
+
+  make[AvailablePort].named("kafka").tagged(Env.Test).from {
+    kafka: KafkaDocker.Container =>
+      kafka.availablePorts(KafkaDocker.primaryPort).head
+  }
+
   // this container will start once `DynamoContainer` is up and running
   make[PostgresDocker.Container].fromResource {
-    PostgresDocker.make[Task]
-      .dependOnDocker(DynamoDocker)
+    PostgresDocker.make[Task].dependOnDocker(DynamoDocker)
   }
 
   // these lines are for test scope
diff --git a/distage/distage-framework/src/test/scala/izumi/distage/roles/test/RoleAppTest.scala b/distage/distage-framework/src/test/scala/izumi/distage/roles/test/RoleAppTest.scala
index e02e55b87..fed8db566 100644
--- a/distage/distage-framework/src/test/scala/izumi/distage/roles/test/RoleAppTest.scala
+++ b/distage/distage-framework/src/test/scala/izumi/distage/roles/test/RoleAppTest.scala
@@ -145,7 +145,7 @@ class RoleAppTest extends AnyWordSpec
         many[TestResource]
           .ref[TestResource]
       } ++ IdentityDIEffectModule ++ probe
-      val roots = Set(DIKey.get[Set[TestResource]] : DIKey)
+      val roots = Set(DIKey.get[Set[TestResource]]: DIKey)
       val roleAppPlanner = new RoleAppPlanner.Impl[Identity](
         PlanningOptions(),
         BootstrapModule.empty,
@@ -181,7 +181,7 @@ class RoleAppTest extends AnyWordSpec
         many[TestResource]
           .ref[TestResource]
       } ++ IdentityDIEffectModule ++ probe
-      val roots = Set(DIKey.get[Set[TestResource]] : DIKey)
+      val roots = Set(DIKey.get[Set[TestResource]]: DIKey)
       val roleAppPlanner = new RoleAppPlanner.Impl[Identity](
         PlanningOptions(),
         BootstrapModule.empty,
@@ -217,7 +217,7 @@ class RoleAppTest extends AnyWordSpec
           .ref[TestResource with AutoCloseable]
         make[XXX_ResourceEffectsRecorder].fromValue(initCounter)
       } ++ IdentityDIEffectModule
-      val roots = Set(DIKey.get[Set[TestResource]] : DIKey)
+      val roots = Set(DIKey.get[Set[TestResource]]: DIKey)
       val roleAppPlanner = new RoleAppPlanner.Impl[Identity](
         PlanningOptions(),
         BootstrapModule.empty,
diff --git a/distage/distage-testkit-core/src/main/scala/izumi/distage/testkit/services/DISyntaxZIOEnv.scala b/distage/distage-testkit-core/src/main/scala/izumi/distage/testkit/services/DISyntaxZIOEnv.scala
index 477d3992f..4406a664c 100644
--- a/distage/distage-testkit-core/src/main/scala/izumi/distage/testkit/services/DISyntaxZIOEnv.scala
+++ b/distage/distage-testkit-core/src/main/scala/izumi/distage/testkit/services/DISyntaxZIOEnv.scala
@@ -45,11 +45,11 @@ import scala.language.implicitConversions
   */
 trait DISyntaxZIOEnv {
   implicit def zioToFn[R: TraitConstructor, E: Tag, A: Tag](zio: ZIO[R, E, A]): ProviderMagnet[IO[E, A]] = {
-    TraitConstructor[R].provider.map(zio.provide)
+    TraitConstructor[R].map(zio.provide)
   }
 
   def args[R: Tag: TraitConstructor, E: Tag, A: Tag](zio: ProviderMagnet[ZIO[R, E, A]]): ProviderMagnet[IO[E, A]] = {
-    zio.map2(TraitConstructor[R].provider)(_.provide(_))
+    zio.map2(TraitConstructor[R])(_.provide(_))
   }
 }
 
diff --git a/distage/distage-testkit-core/src/main/scala/izumi/distage/testkit/services/dstest/DistageTestRunner.scala b/distage/distage-testkit-core/src/main/scala/izumi/distage/testkit/services/dstest/DistageTestRunner.scala
index e7d807a43..8da766635 100644
--- a/distage/distage-testkit-core/src/main/scala/izumi/distage/testkit/services/dstest/DistageTestRunner.scala
+++ b/distage/distage-testkit-core/src/main/scala/izumi/distage/testkit/services/dstest/DistageTestRunner.scala
@@ -90,7 +90,8 @@ class DistageTestRunner[F[_]: TagK]
           distageTest =>
             val keys = distageTest.test.get.diKeys.toSet
             val testRoots = keys ++ env.forcedRoots
-            distageTest -> injector.plan(PlannerInput(appModule, testRoots))
+            val plan = if (testRoots.nonEmpty) injector.plan(PlannerInput(appModule, testRoots)) else OrderedPlan.empty
+            distageTest -> plan
         }
 
         val wholeEnvKeys = testPlans.flatMap(_._2.steps).map(_.target).toSet
diff --git a/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/AssertBIO.scala b/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/AssertBIO.scala
index 5a663babe..03d45a61e 100644
--- a/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/AssertBIO.scala
+++ b/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/AssertBIO.scala
@@ -3,7 +3,8 @@ package izumi.distage.testkit.scalatest
 import izumi.distage.testkit.scalatest.AssertBIO.AssertBIOMacro
 import izumi.functional.bio.BIO
 import org.scalactic.{Prettifier, source}
-import org.scalatest.{Assertion, DistageAssertionsMacro}
+import org.scalatest.Assertion
+import org.scalatest.distage.DistageAssertionsMacro
 
 import scala.language.experimental.macros
 import scala.reflect.macros.blackbox
diff --git a/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/AssertCIO.scala b/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/AssertCIO.scala
index b618bc5e6..a2602055b 100644
--- a/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/AssertCIO.scala
+++ b/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/AssertCIO.scala
@@ -4,7 +4,8 @@ import cats.effect.IO
 import izumi.distage.testkit.scalatest.AssertCIO.AssertCIOMacro
 import org.scalactic.Prettifier
 import org.scalactic.source.Position
-import org.scalatest.{Assertion, DistageAssertionsMacro}
+import org.scalatest.Assertion
+import org.scalatest.distage.DistageAssertionsMacro
 
 import scala.language.experimental.macros
 import scala.reflect.macros.blackbox
diff --git a/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/AssertIO.scala b/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/AssertIO.scala
index 2f80778db..5a857008e 100644
--- a/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/AssertIO.scala
+++ b/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/AssertIO.scala
@@ -3,7 +3,8 @@ package izumi.distage.testkit.scalatest
 import izumi.distage.testkit.scalatest.AssertIO.AssertIOMacro
 import org.scalactic.Prettifier
 import org.scalactic.source.Position
-import org.scalatest.{Assertion, DistageAssertionsMacro}
+import org.scalatest.Assertion
+import org.scalatest.distage.DistageAssertionsMacro
 import zio.IO
 
 import scala.language.experimental.macros
diff --git a/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/DistageBIOSpecScalatest.scala b/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/DistageBIOSpecScalatest.scala
index 7e462c4cc..1a999ce1d 100644
--- a/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/DistageBIOSpecScalatest.scala
+++ b/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/DistageBIOSpecScalatest.scala
@@ -3,7 +3,7 @@ package izumi.distage.testkit.scalatest
 import distage.TagKK
 import izumi.distage.testkit.services.scalatest.dstest.DistageAbstractScalatestSpec
 import izumi.distage.testkit.services.scalatest.dstest.DistageAbstractScalatestSpec.{DSWordSpecStringWrapper, DSWordSpecStringWrapper2}
-import org.scalatest.DistageScalatestTestSuiteRunner
+import org.scalatest.distage.DistageScalatestTestSuiteRunner
 
 import scala.language.implicitConversions
 
@@ -11,7 +11,7 @@ abstract class DistageBIOSpecScalatest[F[+_, +_]](implicit val tagBIO: TagKK[F])
   extends DistageScalatestTestSuiteRunner[F[Throwable, ?]]
     with DistageAbstractScalatestSpec[F[Throwable, ?]] {
 
-  protected implicit def convertToWordSpecStringWrapper2(s: String): DSWordSpecStringWrapper2[F] = {
+  protected implicit def convertToWordSpecStringWrapperDS2(s: String): DSWordSpecStringWrapper2[F] = {
     new DSWordSpecStringWrapper2(context, distageSuiteName, distageSuiteId, s, this, testEnv)
   }
 
diff --git a/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/DistageSpecScalatest.scala b/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/DistageSpecScalatest.scala
index 88e187b34..7076acab1 100644
--- a/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/DistageSpecScalatest.scala
+++ b/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/scalatest/DistageSpecScalatest.scala
@@ -2,7 +2,7 @@ package izumi.distage.testkit.scalatest
 
 import distage.TagK
 import izumi.distage.testkit.services.scalatest.dstest.DistageAbstractScalatestSpec
-import org.scalatest.DistageScalatestTestSuiteRunner
+import org.scalatest.distage.DistageScalatestTestSuiteRunner
 
 abstract class DistageSpecScalatest[F[_]: TagK]
   extends DistageScalatestTestSuiteRunner[F]
diff --git a/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/services/scalatest/dstest/DistageAbstractScalatestSpec.scala b/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/services/scalatest/dstest/DistageAbstractScalatestSpec.scala
index e58f8a916..fea7553fa 100644
--- a/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/services/scalatest/dstest/DistageAbstractScalatestSpec.scala
+++ b/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/services/scalatest/dstest/DistageAbstractScalatestSpec.scala
@@ -1,6 +1,6 @@
 package izumi.distage.testkit.services.scalatest.dstest
 
-import distage.{Tag, TagK, TagKK}
+import distage.{TagK, TagKK}
 import izumi.distage.model.effect.DIEffect
 import izumi.distage.model.providers.ProviderMagnet
 import izumi.distage.testkit.TestConfig
@@ -8,10 +8,12 @@ import izumi.distage.testkit.services.dstest.DistageTestRunner.{DistageTest, Tes
 import izumi.distage.testkit.services.dstest._
 import izumi.distage.testkit.services.scalatest.dstest.DistageAbstractScalatestSpec._
 import izumi.distage.testkit.services.{DISyntaxBIOBase, DISyntaxBase}
-import izumi.fundamentals.platform.language.{CodePosition, CodePositionMaterializer, Quirks, unused}
+import izumi.fundamentals.platform.language.{CodePosition, CodePositionMaterializer, unused}
 import izumi.logstage.api.{IzLogger, Log}
 import org.scalactic.source
-import org.scalatest.{Assertion, TestCancellation}
+import org.scalatest.Assertion
+import org.scalatest.distage.TestCancellation
+import org.scalatest.verbs.{CanVerb, MustVerb, ShouldVerb, StringVerbBlockRegistration}
 
 import scala.language.implicitConversions
 
@@ -25,8 +27,9 @@ trait WithSingletonTestRegistration[F[_]] extends AbstractDistageSpec[F] {
   }
 }
 
+@org.scalatest.Finders(value = Array("org.scalatest.finders.WordSpecFinder"))
 trait DistageAbstractScalatestSpec[F[_]]
-  extends ScalatestWords
+  extends ShouldVerb with MustVerb with CanVerb
     with DistageTestEnv
     with WithSingletonTestRegistration[F] {
   this: AbstractDistageSpec[F] =>
@@ -42,15 +45,19 @@ trait DistageAbstractScalatestSpec[F[_]]
   protected def distageSuiteId: String = this.getClass.getName
 
   //
-  protected[distage] var context: Option[SuiteContext] = None
+  private[distage] var context: Option[SuiteContext] = None
 
-  override def registerBranch(description: String, childPrefix: Option[String], verb: String, methodName: String, stackDepth: Int, adjustment: Int, pos: source.Position, fun: () => Unit): Unit = {
-    Quirks.discard(childPrefix, methodName, stackDepth, adjustment, pos)
+  implicit val subjectRegistrationFunction1: StringVerbBlockRegistration = new StringVerbBlockRegistration {
+    override def apply(left: String, verb: String, @unused pos: source.Position, f: () => Unit): Unit = {
+      registerBranch(left, verb, f)
+    }
+  }
+
+  protected def registerBranch(description: String, verb: String, fun: () => Unit): Unit = {
     this.context = Some(SuiteContext(description, verb))
     fun()
     this.context = None
   }
-  //
 
   protected implicit def convertToWordSpecStringWrapperDS(s: String): DSWordSpecStringWrapper[F] = {
     new DSWordSpecStringWrapper(context, distageSuiteName, distageSuiteId, s, this, testEnv)
@@ -64,6 +71,24 @@ object DistageAbstractScalatestSpec {
     }
   }
 
+  trait LowPriorityIdentityOverloads[F[_]] extends DISyntaxBase[F] {
+    def in(function: ProviderMagnet[Unit])(implicit pos: CodePositionMaterializer, d1: DummyImplicit, d2: DummyImplicit): Unit = {
+      takeAny(function, pos.get)
+    }
+
+    def in(function: ProviderMagnet[Assertion])(implicit pos: CodePositionMaterializer, d1: DummyImplicit, d2: DummyImplicit, d3: DummyImplicit): Unit = {
+      takeAny(function, pos.get)
+    }
+
+    def in(value: => Unit)(implicit pos: CodePositionMaterializer, d1: DummyImplicit, d2: DummyImplicit): Unit = {
+      takeAny(() => value, pos.get)
+    }
+
+    def in(value: => Assertion)(implicit pos: CodePositionMaterializer, d1: DummyImplicit, d2: DummyImplicit, d3: DummyImplicit): Unit = {
+      takeAny(() => value, pos.get)
+    }
+  }
+
   class DSWordSpecStringWrapper[F[_]](
                                        context: Option[SuiteContext],
                                        suiteName: String,
@@ -73,7 +98,7 @@ object DistageAbstractScalatestSpec {
                                        env: TestEnvironment,
                                      )(
                                        implicit override val tagMonoIO: TagK[F],
-                                     ) extends DISyntaxBase[F] {
+                                     ) extends DISyntaxBase[F] with LowPriorityIdentityOverloads[F] {
 
     override protected def takeIO(function: ProviderMagnet[F[_]], pos: CodePosition): Unit = {
       val id = TestId(
@@ -85,51 +110,23 @@ object DistageAbstractScalatestSpec {
       reg.registerTest(function, env, pos, id)
     }
 
-    def in(function: ProviderMagnet[F[_]])(implicit pos: CodePositionMaterializer): Unit = {
+    def in(function: ProviderMagnet[F[Unit]])(implicit pos: CodePositionMaterializer): Unit = {
       takeIO(function, pos.get)
     }
 
-    def in(function: ProviderMagnet[_])(implicit pos: CodePositionMaterializer, dummyImplicit: DummyImplicit): Unit = {
-      takeAny(function, pos.get)
+    def in(function: ProviderMagnet[F[Assertion]])(implicit pos: CodePositionMaterializer, d1: DummyImplicit): Unit = {
+      takeIO(function, pos.get)
     }
 
-    def in(value: => F[_])(implicit pos: CodePositionMaterializer): Unit = {
+    def in(value: => F[Unit])(implicit pos: CodePositionMaterializer): Unit = {
       takeIO(() => value, pos.get)
     }
 
-    def in(value: => Unit)(implicit pos: CodePositionMaterializer, dummyImplicit: DummyImplicit): Unit = {
-      takeAny(() => value, pos.get)
-    }
-
-    def in(value: => Assertion)(implicit pos: CodePositionMaterializer, dummyImplicit: DummyImplicit, dummyImplicit2: DummyImplicit): Unit = {
-      takeAny(() => value, pos.get)
-    }
-
-    def skip(@unused function: ProviderMagnet[F[_]])(implicit pos: CodePositionMaterializer): Unit = {
-      takeFunIO(cancel, pos.get)
-    }
-
-    def skip(@unused function: ProviderMagnet[_])(implicit pos: CodePositionMaterializer, dummyImplicit: DummyImplicit): Unit = {
-      takeFunIO(cancel, pos.get)
-    }
-
-    def skip[T: Tag](@unused function: T => F[_])(implicit pos: CodePositionMaterializer): Unit = {
-      takeFunIO(cancel, pos.get)
-    }
-
-    def skip[T: Tag](@unused function: T => _)(implicit pos: CodePositionMaterializer, dummyImplicit: DummyImplicit): Unit = {
-      takeFunIO(cancel, pos.get)
-    }
-
-    def skip(@unused value: => F[_])(implicit pos: CodePositionMaterializer): Unit = {
-      takeFunIO(cancel, pos.get)
-    }
-
-    def skip(@unused value: => Unit)(implicit pos: CodePositionMaterializer, dummyImplicit: DummyImplicit): Unit = {
-      takeFunIO(cancel, pos.get)
+    def in(value: => F[Assertion])(implicit pos: CodePositionMaterializer, d1: DummyImplicit): Unit = {
+      takeIO(() => value, pos.get)
     }
 
-    def skip(@unused value: => Assertion)(implicit pos: CodePositionMaterializer, dummyImplicit: DummyImplicit, dummyImplicit2: DummyImplicit): Unit = {
+    def skip(@unused value: => Any)(implicit pos: CodePositionMaterializer): Unit = {
       takeFunIO(cancel, pos.get)
     }
 
@@ -151,7 +148,7 @@ object DistageAbstractScalatestSpec {
                                              env: TestEnvironment,
                                            )(
                                              implicit override val tagBIO: TagKK[F],
-                                           ) extends DISyntaxBIOBase[F] {
+                                           ) extends DISyntaxBIOBase[F] with LowPriorityIdentityOverloads[F[Throwable, ?]] {
     override val tagMonoIO: TagK[F[Throwable, ?]] = TagK[F[Throwable, ?]]
 
     override protected def takeIO(fAsThrowable: ProviderMagnet[F[Throwable, _]], pos: CodePosition): Unit = {
@@ -164,51 +161,23 @@ object DistageAbstractScalatestSpec {
       reg.registerTest(fAsThrowable, env, pos, id)
     }
 
-    def in(function: ProviderMagnet[F[_, _]])(implicit pos: CodePositionMaterializer): Unit = {
+    def in(function: ProviderMagnet[F[_, Unit]])(implicit pos: CodePositionMaterializer): Unit = {
       takeBIO(function, pos.get)
     }
 
-    def in(function: ProviderMagnet[_])(implicit pos: CodePositionMaterializer, dummyImplicit: DummyImplicit): Unit = {
-      takeAny(function, pos.get)
+    def in(function: ProviderMagnet[F[_, Assertion]])(implicit pos: CodePositionMaterializer, d1: DummyImplicit): Unit = {
+      takeBIO(function, pos.get)
     }
 
-    def in(value: => F[_, _])(implicit pos: CodePositionMaterializer): Unit = {
+    def in(value: => F[_, Unit])(implicit pos: CodePositionMaterializer): Unit = {
       takeBIO(() => value, pos.get)
     }
 
-    def in(value: => Unit)(implicit pos: CodePositionMaterializer, dummyImplicit: DummyImplicit): Unit = {
-      takeAny(() => value, pos.get)
-    }
-
-    def in(value: => Assertion)(implicit pos: CodePositionMaterializer, dummyImplicit: DummyImplicit, dummyImplicit2: DummyImplicit): Unit = {
-      takeAny(() => value, pos.get)
-    }
-
-    def skip(@unused function: ProviderMagnet[F[_, _]])(implicit pos: CodePositionMaterializer): Unit = {
-      takeFunIO(cancel, pos.get)
-    }
-
-    def skip(@unused function: ProviderMagnet[_])(implicit pos: CodePositionMaterializer, dummyImplicit: DummyImplicit): Unit = {
-      takeFunIO(cancel, pos.get)
-    }
-
-    def skip[T: Tag](@unused function: T => F[_, _])(implicit pos: CodePositionMaterializer): Unit = {
-      takeFunIO(cancel, pos.get)
-    }
-
-    def skip[T: Tag](@unused function: T => _)(implicit pos: CodePositionMaterializer, dummyImplicit: DummyImplicit): Unit = {
-      takeFunIO(cancel, pos.get)
-    }
-
-    def skip(@unused value: => F[_, _])(implicit pos: CodePositionMaterializer): Unit = {
-      takeFunIO(cancel, pos.get)
-    }
-
-    def skip(@unused value: => Unit)(implicit pos: CodePositionMaterializer, dummyImplicit: DummyImplicit): Unit = {
-      takeFunIO(cancel, pos.get)
+    def in(value: => F[_, Assertion])(implicit pos: CodePositionMaterializer, d1: DummyImplicit): Unit = {
+      takeBIO(() => value, pos.get)
     }
 
-    def skip(@unused value: => Assertion)(implicit pos: CodePositionMaterializer, dummyImplicit: DummyImplicit, dummyImplicit2: DummyImplicit): Unit = {
+    def skip(@unused value: => Any)(implicit pos: CodePositionMaterializer): Unit = {
       takeFunIO(cancel, pos.get)
     }
 
diff --git a/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/SafeTestReporter.scala b/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/services/scalatest/dstest/SafeTestReporter.scala
similarity index 98%
rename from distage/distage-testkit-scalatest/src/main/scala/org/scalatest/SafeTestReporter.scala
rename to distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/services/scalatest/dstest/SafeTestReporter.scala
index b973ef0e9..389fa6243 100644
--- a/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/SafeTestReporter.scala
+++ b/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/services/scalatest/dstest/SafeTestReporter.scala
@@ -1,4 +1,4 @@
-package org.scalatest
+package izumi.distage.testkit.services.scalatest.dstest
 
 import izumi.distage.testkit.services.dstest.DistageTestRunner.TestStatus.{Done, Running}
 import izumi.distage.testkit.services.dstest.DistageTestRunner.{SuiteData, TestMeta, TestReporter, TestStatus}
diff --git a/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/services/scalatest/dstest/ScalatestWords.scala b/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/services/scalatest/dstest/ScalatestWords.scala
deleted file mode 100644
index 8a52e5149..000000000
--- a/distage/distage-testkit-scalatest/src/main/scala/izumi/distage/testkit/services/scalatest/dstest/ScalatestWords.scala
+++ /dev/null
@@ -1,135 +0,0 @@
-package izumi.distage.testkit.services.scalatest.dstest
-
-import izumi.distage.testkit.services.scalatest.dstest.ScalatestWords.{DSCanVerb, DSMustVerb, DSShouldVerb, DSStringVerbBlockRegistration}
-import org.scalactic.source
-import org.scalactic.source.Position
-
-@org.scalatest.Finders(value = Array("org.scalatest.finders.WordSpecFinder"))
-trait ScalatestWords extends DSShouldVerb with DSMustVerb with DSCanVerb  {
-  protected implicit val subjectRegistrationFunction1: DSStringVerbBlockRegistration = new DSStringVerbBlockRegistration {
-    def apply(left: String, verb: String, pos: source.Position, f: () => Unit): Unit = {
-      registerBranch(left, Some(verb), verb, "apply", 6, -2, pos, f)
-    }
-  }
-
-  def registerBranch(description: String, childPrefix: Option[String], verb: String, methodName: String, stackDepth: Int, adjustment: Int, pos: source.Position, fun: () => Unit): Unit
-}
-
-object ScalatestWords {
-
-  // shameless copypaste from ScalaTest
-
-  abstract class DSStringVerbBlockRegistration {
-    def apply(string: String, verb: String, pos: source.Position, block: () => Unit): Unit
-  }
-
-  abstract class DSStringVerbStringInvocation {
-    def apply(subject: String, verb: String, predicate: String, pos: source.Position): DSResultOfStringPassedToVerb
-  }
-
-  abstract class DSResultOfStringPassedToVerb(val verb: String, val rest: String) {
-    //def taggedAs(firstTestTag: Tag, otherTestTags: Tag*): ResultOfTaggedAsInvocation
-  }
-
-  final class DSResultOfAfterWordApplication(val text: String, val f: () => Unit) {
-    override def toString: String = text
-  }
-
-  abstract class DSSubjectWithAfterWordRegistration {
-    def apply(subject: String, verb: String, resultOfAfterWordApplication: DSResultOfAfterWordApplication, pos: source.Position): Unit
-  }
-
-
-  trait DSShouldVerb {
-
-    trait DSStringShouldWrapperForVerb {
-
-      val leftSideString: String
-
-      val pos: source.Position
-
-      def should(right: String)(implicit svsi: DSStringVerbStringInvocation): DSResultOfStringPassedToVerb = {
-        svsi(leftSideString, "should", right, pos)
-      }
-
-      def should(right: => Unit)(implicit fun: DSStringVerbBlockRegistration): Unit = {
-        fun(leftSideString, "should", pos, right _)
-      }
-
-      def should(resultOfAfterWordApplication: DSResultOfAfterWordApplication)(implicit swawr: DSSubjectWithAfterWordRegistration): Unit = {
-        swawr(leftSideString, "should", resultOfAfterWordApplication, pos)
-      }
-    }
-
-    import scala.language.implicitConversions
-
-    implicit def convertToStringShouldWrapperForVerb(o: String)(implicit position: source.Position): DSStringShouldWrapperForVerb =
-      new DSStringShouldWrapperForVerb {
-        val leftSideString: String = o.trim
-        val pos: Position = position
-      }
-  }
-
-
-  trait DSCanVerb {
-
-    trait DSStringCanWrapperForVerb {
-
-      val leftSideString: String
-
-      val pos: source.Position
-
-      def can(right: String)(implicit svsi: DSStringVerbStringInvocation): DSResultOfStringPassedToVerb = {
-        svsi(leftSideString, "can", right, pos)
-      }
-
-      def can(right: => Unit)(implicit fun: DSStringVerbBlockRegistration): Unit = {
-        fun(leftSideString, "can", pos, right _)
-      }
-
-      def can(resultOfAfterWordApplication: DSResultOfAfterWordApplication)(implicit swawr: DSSubjectWithAfterWordRegistration): Unit = {
-        swawr(leftSideString, "can", resultOfAfterWordApplication, pos)
-      }
-    }
-
-    import scala.language.implicitConversions
-
-    implicit def convertToStringCanWrapper(o: String)(implicit position: source.Position): DSStringCanWrapperForVerb =
-      new DSStringCanWrapperForVerb {
-        val leftSideString: String = o.trim
-        val pos: Position = position
-      }
-  }
-
-  trait DSMustVerb {
-
-    trait DSStringMustWrapperForVerb {
-
-      val leftSideString: String
-
-      val pos: source.Position
-
-      def must(right: String)(implicit svsi: DSStringVerbStringInvocation): DSResultOfStringPassedToVerb = {
-        svsi(leftSideString, "must", right, pos)
-      }
-
-      def must(right: => Unit)(implicit fun: DSStringVerbBlockRegistration): Unit = {
-        fun(leftSideString, "must", pos, right _)
-      }
-
-      def must(resultOfAfterWordApplication: DSResultOfAfterWordApplication)(implicit swawr: DSSubjectWithAfterWordRegistration): Unit = {
-        swawr(leftSideString, "must", resultOfAfterWordApplication, pos)
-      }
-    }
-
-    import scala.language.implicitConversions
-
-    implicit def convertToStringMustWrapperForVerb(o: String)(implicit position: source.Position): DSStringMustWrapperForVerb =
-      new DSStringMustWrapperForVerb {
-        val leftSideString: String = o.trim
-        val pos: Position = position
-      }
-  }
-
-
-}
diff --git a/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/DistageAssertionsMacro.scala b/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/distage/DistageAssertionsMacro.scala
similarity index 90%
rename from distage/distage-testkit-scalatest/src/main/scala/org/scalatest/DistageAssertionsMacro.scala
rename to distage/distage-testkit-scalatest/src/main/scala/org/scalatest/distage/DistageAssertionsMacro.scala
index 71a380f18..b13c324d7 100644
--- a/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/DistageAssertionsMacro.scala
+++ b/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/distage/DistageAssertionsMacro.scala
@@ -1,7 +1,8 @@
-package org.scalatest
+package org.scalatest.distage
 
 import org.scalactic.Prettifier
 import org.scalactic.source.Position
+import org.scalatest.{Assertion, AssertionsMacro}
 
 import scala.reflect.macros.{blackbox, whitebox}
 
diff --git a/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/DistageScalatestReporter.scala b/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/distage/DistageScalatestReporter.scala
similarity index 99%
rename from distage/distage-testkit-scalatest/src/main/scala/org/scalatest/DistageScalatestReporter.scala
rename to distage/distage-testkit-scalatest/src/main/scala/org/scalatest/distage/DistageScalatestReporter.scala
index fa6ff71e5..55c8e8e45 100644
--- a/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/DistageScalatestReporter.scala
+++ b/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/distage/DistageScalatestReporter.scala
@@ -1,4 +1,4 @@
-package org.scalatest
+package org.scalatest.distage
 
 import izumi.distage.framework.model.exceptions.IntegrationCheckException
 import izumi.distage.testkit.services.dstest.DistageTestRunner.{SuiteData, TestMeta, TestReporter, TestStatus}
diff --git a/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/DistageScalatestTestSuiteRunner.scala b/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/distage/DistageScalatestTestSuiteRunner.scala
similarity index 95%
rename from distage/distage-testkit-scalatest/src/main/scala/org/scalatest/DistageScalatestTestSuiteRunner.scala
rename to distage/distage-testkit-scalatest/src/main/scala/org/scalatest/distage/DistageScalatestTestSuiteRunner.scala
index 6f72b0e92..50eb81c6b 100644
--- a/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/DistageScalatestTestSuiteRunner.scala
+++ b/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/distage/DistageScalatestTestSuiteRunner.scala
@@ -1,4 +1,4 @@
-package org.scalatest
+package org.scalatest.distage
 
 import java.util.concurrent.atomic.AtomicBoolean
 
@@ -7,10 +7,11 @@ import io.github.classgraph.ClassGraph
 import izumi.distage.testkit.DebugProperties
 import izumi.distage.testkit.services.dstest.DistageTestRunner._
 import izumi.distage.testkit.services.dstest.{AbstractDistageSpec, DistageTestRunner}
-import izumi.distage.testkit.services.scalatest.dstest.DistageTestsRegistrySingleton
+import izumi.distage.testkit.services.scalatest.dstest.{DistageTestsRegistrySingleton, SafeTestReporter}
 import izumi.distage.testkit.services.scalatest.dstest.DistageTestsRegistrySingleton.SuiteReporter
 import izumi.fundamentals.platform.console.TrivialLogger
 import izumi.fundamentals.platform.functional.Identity
+import org.scalatest._
 import org.scalatest.exceptions.TestCanceledException
 
 import scala.collection.immutable.TreeSet
@@ -66,7 +67,7 @@ object ScalatestInitWorkaround {
 
 }
 
-abstract class DistageScalatestTestSuiteRunner[F[_]](implicit override val tagMonoIO: TagK[F]) extends Suite with AbstractDistageSpec[F] {
+abstract class DistageScalatestTestSuiteRunner[F[_]](implicit override val tagMonoIO: TagK[F]) extends TestSuite with AbstractDistageSpec[F] {
 
   // initialize status early, so that runner can set it to `true` even before this test is discovered
   // by scalatest, if it was already executed by that time
@@ -75,6 +76,7 @@ abstract class DistageScalatestTestSuiteRunner[F[_]](implicit override val tagMo
   override protected final def runNestedSuites(args: Args): Status = throw new UnsupportedOperationException
   override protected final def runTests(testName: Option[String], args: Args): Status = throw new UnsupportedOperationException
   override protected final def runTest(testName: String, args: Args): Status = throw new UnsupportedOperationException
+  override protected def withFixture(test: NoArgTest): Outcome = throw new UnsupportedOperationException
 
   override def run(testName: Option[String], args: Args): Status = {
     DistageTestsRegistrySingleton.registerSuiteReporter(suiteId)(SuiteReporter(args.tracker, args.reporter))
diff --git a/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/TestCancellation.scala b/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/distage/TestCancellation.scala
similarity index 93%
rename from distage/distage-testkit-scalatest/src/main/scala/org/scalatest/TestCancellation.scala
rename to distage/distage-testkit-scalatest/src/main/scala/org/scalatest/distage/TestCancellation.scala
index 2b8e62d07..a8deb9da3 100644
--- a/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/TestCancellation.scala
+++ b/distage/distage-testkit-scalatest/src/main/scala/org/scalatest/distage/TestCancellation.scala
@@ -1,4 +1,4 @@
-package org.scalatest
+package org.scalatest.distage
 
 import org.scalatest.exceptions.TestCanceledException
 
diff --git a/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/DistageTestExample.scala b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/DistageTestExample.scala
index 6aa2b50d8..632131138 100644
--- a/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/DistageTestExample.scala
+++ b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/DistageTestExample.scala
@@ -115,6 +115,10 @@ abstract class DistageTestExampleBase[F[_]: TagK](implicit F: DIEffect[F]) exten
         F.maybeSuspend(assert(set.size == 3))
     }
 
+    "support tests with no deps" in {
+      F.unit
+    }
+
     "test 1" in {
       service: MockUserRepository[F] =>
         for {
@@ -144,12 +148,12 @@ abstract class DistageTestExampleBase[F[_]: TagK](implicit F: DIEffect[F]) exten
 
     "test 4 (should be ignored)" in {
       _: ApplePaymentProvider[F] =>
-        ???
+        assert(false)
     }
 
     "test 5 (should be ignored)" skip {
       _: MockCachedUserService[F] =>
-        ???
+        assert(false)
     }
 
     "test 6 (should be ignored)" in {
diff --git a/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/IdentityCompatTest.scala b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/IdentityCompatTest.scala
new file mode 100644
index 000000000..8dbc884df
--- /dev/null
+++ b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/IdentityCompatTest.scala
@@ -0,0 +1,24 @@
+package izumi.distage.testkit.distagesuite
+
+import izumi.distage.model.effect.DIEffect
+import izumi.distage.testkit.scalatest.DistageSpecScalatest
+import izumi.fundamentals.platform.functional.Identity
+
+final class IdentityCompatTest extends DistageSpecScalatest[Identity] {
+
+  "tests in identity" should {
+
+    "start" in {
+      _: DIEffect[Identity] =>
+        assert(true)
+        println("identitycompat")
+    }
+
+    "skip (should be ignored)" in {
+      _: DIEffect[Identity] =>
+        assume(false)
+    }
+
+  }
+
+}
diff --git a/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/ScalaMockCompatTest.scala b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/ScalaMockCompatTest.scala
new file mode 100644
index 000000000..2440dd471
--- /dev/null
+++ b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/ScalaMockCompatTest.scala
@@ -0,0 +1,29 @@
+package izumi.distage.testkit.distagesuite
+
+import distage.ModuleDef
+import izumi.distage.testkit.TestConfig
+import izumi.distage.testkit.scalatest.DistageSpecScalatest
+import izumi.fundamentals.platform.functional.Identity
+import org.scalamock.scalatest.MockFactory
+
+final class ScalaMockCompatTest extends DistageSpecScalatest[Identity] with MockFactory {
+
+  trait TestClass {
+    def method: String
+  }
+
+  override protected def config: TestConfig = super.config.copy(
+    moduleOverrides = new ModuleDef {
+      make[TestClass].from(mock[TestClass])
+    }
+  )
+
+  "mockfactory" should {
+    "be compatible" in {
+      testMock: TestClass =>
+        (testMock.method _).expects().returning("hello")
+        assert(testMock.method == "hello")
+    }
+  }
+
+}
diff --git a/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/ScalatestCompatTest.scala b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/ScalatestCompatTest.scala
new file mode 100644
index 000000000..34475745e
--- /dev/null
+++ b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/ScalatestCompatTest.scala
@@ -0,0 +1,32 @@
+package izumi.distage.testkit.distagesuite
+
+import izumi.distage.testkit.scalatest.{AssertIO, DistageSpecScalatest}
+import izumi.fundamentals.platform.functional.Identity
+import org.scalatest.exceptions.TestFailedException
+import org.scalatest.matchers.{must, should}
+
+final class ScalatestCompatTestShould extends DistageSpecScalatest[Identity] with should.Matchers with AssertIO {
+
+  "test" should {
+    "start" in {
+      intercept[TestFailedException](1 should equal(5))
+      1 should equal(1)
+      1 should equal(1)
+      1 should not equal 2
+    }
+  }
+
+}
+
+final class ScalatestCompatTestMust extends DistageSpecScalatest[Identity] with must.Matchers with AssertIO {
+
+  "test" should {
+    "start" in {
+      intercept[TestFailedException](1 must equal(5))
+      1 must equal(1)
+      1 must equal(1)
+      1 must not equal 2
+    }
+  }
+
+}
diff --git a/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/fixtures/Fixtures.scala b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/fixtures/Fixtures.scala
index fd4e0dd89..925136419 100644
--- a/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/fixtures/Fixtures.scala
+++ b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/fixtures/Fixtures.scala
@@ -24,7 +24,7 @@ object MockAppCatsIOPlugin extends MockAppPlugin[CIO]
 object MockAppZioPlugin extends MockAppPlugin[Task]
 object MockAppIdPlugin extends MockAppPlugin[Identity]
 
-abstract class MockAppPlugin[F[_] : TagK] extends PluginDef {
+abstract class MockAppPlugin[F[_]: TagK] extends PluginDef {
   make[MockPostgresDriver[F]]
   make[MockUserRepository[F]]
   make[MockPostgresCheck[F]]
diff --git a/fundamentals/fundamentals-bio/.jvm/src/test/scala/izumi/functional/bio/test/BlockingIOSyntaxTest.scala b/fundamentals/fundamentals-bio/.jvm/src/test/scala/izumi/functional/bio/test/BlockingIOSyntaxTest.scala
index d26d38892..a03bd8205 100644
--- a/fundamentals/fundamentals-bio/.jvm/src/test/scala/izumi/functional/bio/test/BlockingIOSyntaxTest.scala
+++ b/fundamentals/fundamentals-bio/.jvm/src/test/scala/izumi/functional/bio/test/BlockingIOSyntaxTest.scala
@@ -3,7 +3,7 @@ package izumi.functional.bio.test
 import izumi.functional.bio.{BIOFunctor, BlockingIO, BlockingIO3, BlockingIOInstances, F}
 import izumi.fundamentals.bio.test.masking.BIOMonad3
 import org.scalatest.wordspec.AnyWordSpec
-import zio.ZIO
+import zio.{Has, ZIO}
 import zio.blocking.Blocking
 
 class BlockingIOSyntaxTest extends AnyWordSpec {
@@ -15,8 +15,8 @@ class BlockingIOSyntaxTest extends AnyWordSpec {
     F.syncBlocking(2)
   }
   val _: ZIO[Blocking, Throwable, Int] = {
-    implicit val blocking: Blocking = zio.Runtime.unsafeFromLayer(Blocking.live).environment
-    `attach BlockingIO methods to a trifunctor BIO`[BlockingIOInstances.ZIOBlocking#l]
+    implicit val blocking: Blocking = Has(Blocking.Service.live)
+    `attach BlockingIO methods to a trifunctor BIO`[BlockingIOInstances.ZIOWithBlocking]
     `attach BlockingIO methods to a bifunctor BIO`[zio.IO]
   }
 
@@ -30,10 +30,10 @@ class BlockingIOSyntaxTest extends AnyWordSpec {
 
     assert(new X[zio.ZIO[Blocking, +?, +?]].hello != null)
     locally {
-      implicit val blocking: Blocking = zio.Runtime.unsafeFromLayer(Blocking.live).environment
+      implicit val blocking: Blocking = Has(Blocking.Service.live)
       assert(new X[zio.IO].hello != null)
     }
-    assert(new X3[BlockingIOInstances.ZIOBlocking#l].hello != null)
+    assert(new X3[BlockingIOInstances.ZIOWithBlocking].hello != null)
   }
 
 }
diff --git a/fundamentals/fundamentals-json-circe/src/test/scala/izumi/fundamentals/json/circe/WithCirceTest.scala b/fundamentals/fundamentals-json-circe/src/test/scala/izumi/fundamentals/json/circe/WithCirceTest.scala
new file mode 100644
index 000000000..87e1b8c3e
--- /dev/null
+++ b/fundamentals/fundamentals-json-circe/src/test/scala/izumi/fundamentals/json/circe/WithCirceTest.scala
@@ -0,0 +1,126 @@
+package izumi.fundamentals.json.circe
+
+import io.circe
+import io.circe.{Codec, Decoder, Encoder}
+import io.circe.syntax._
+import izumi.fundamentals.json.circe.WithCirceTest.{Cba, Enum, Enum1, Enum2, Nested, Sealed}
+import org.scalatest.wordspec.AnyWordSpec
+
+final class WithCirceTest extends AnyWordSpec {
+
+  "WithCirce" should {
+    "WithCirce works with case classes" in {
+      assert(Cba(1, 2).asJson.as[Cba].right.get == Cba(1, 2))
+      assert(Cba(1, 2).asJson.noSpaces == """{"a":1,"b":2}""")
+    }
+
+    "WithCirce works with (non-nested) sealed traits" in {
+      assert(Sealed(Cba(1, 2)).asJson.as[Sealed].right.get == Sealed(Cba(1, 2)))
+      assert(Sealed(Cba(1, 2)).asJson.noSpaces == """{"Sealed1":{"cba":{"a":1,"b":2}}}""")
+    }
+
+    // workaround https://github.com/milessabin/shapeless/issues/837
+    "WithCirce works with nested sealed traits via delegation" in {
+      assert(Nested(Cba(1, 2)).asJson.as[Nested].right.get == Nested(Cba(1, 2)))
+      assert(Nested(Cba(1, 2)).asJson.noSpaces == """{"Nested1":{"cba":{"a":1,"b":2}}}""")
+    }
+
+    "progression test: WithCirce DOES NOT encode case objects as strings (circe-generic-extras deriveEnumCodec is still required)" in {
+      assert((Enum1: Enum).asJson.as[Enum].right.get == Enum1)
+      assert((Enum2: Enum).asJson.noSpaces != """"Enum2"""")
+      assert((Enum2: Enum).asJson.noSpaces == """{"Enum2":{}}""")
+    }
+
+    "derivations for encoder/decoder" in {
+      final case class Abc(a: Int)
+      implicitly[DerivationDerivedEncoder[Abc]]
+      implicitly[DerivationDerivedDecoder[Abc]]
+      implicitly[DerivationDerivedCodec[Abc]]
+    }
+  }
+
+}
+
+trait Desc {
+  type I1
+  type I1R
+  type I2
+  type I2R
+
+  def extractI1(i1: I1): I1R
+  def extractI2(i2: I2): I2R
+}
+
+object Dummy {
+  implicit def dummy: Dummy.type = this
+}
+
+abstract class deriving[C <: Desc](implicit c: C { type I1 = C#I1; type I2 = C#I2 }, i10: C#I1, i20: C#I2) {
+  implicit val i1: C#I1R = c.extractI1(i10)
+  implicit val i2: C#I2R = c.extractI2(i20)
+}
+final class JustDecoder[A] extends Desc {
+  override type I1 = DerivationDerivedDecoder[A]
+  override type I1R = Decoder[A]
+  override type I2 = Dummy.type
+  override type I2R = Dummy.type
+
+  override def extractI1(i1: DerivationDerivedDecoder[A]): Decoder[A] = i1.value
+  override def extractI2(i2: Dummy.type): Dummy.type = i2
+}
+object JustDecoder {
+  implicit def x[A]: JustDecoder[A] = new JustDecoder[A]
+}
+final class DecoderEncoder[A] extends Desc {
+  override type I1 = DerivationDerivedDecoder[A]
+  override type I1R = Decoder[A]
+  override type I2 = DerivationDerivedEncoder[A]
+  override type I2R = Encoder.AsObject[A]
+
+  override def extractI1(i1: DerivationDerivedDecoder[A]): Decoder[A] = i1.value
+  override def extractI2(i2: DerivationDerivedEncoder[A]): Encoder.AsObject[A] = i2.value
+}
+object DecoderEncoder {
+  implicit def x[A]: DecoderEncoder[A] = new DecoderEncoder[A]
+}
+
+object WithCirceTest {
+
+  final case class Cba(a: Int, b: Int)
+  object Cba extends WithCirce[Cba]
+
+  final case class Cbaa(a: Int, b: Int)
+  object Cbaa extends deriving[JustDecoder[Cbaa]]
+
+  final case class Cbaaa(a: Int, b: Int)
+  object Cbaaa extends deriving[DecoderEncoder[Cbaa]]
+
+  sealed trait Sealed
+  object Sealed extends WithCirce[Sealed] {
+    def apply(cba: Cba): Sealed = Sealed1(cba)
+  }
+
+  final case class Sealed1(cba: Cba) extends Sealed
+  object Sealed1 extends WithCirce[Sealed1]
+
+  sealed trait Nested
+  object Nested extends WithCirce[Nested](codecs) {
+    def apply(cba: Cba): Nested = Nested1(cba)
+
+    final case class Nested1(cba: Cba) extends Nested
+    object Nested1 extends WithCirce[Nested1]
+  }
+
+  // workaround https://github.com/milessabin/shapeless/issues/837
+  private[this] object codecs extends WithCirce[Nested]
+
+  sealed trait Enum
+  object Enum extends WithCirce[Enum]
+  case object Enum1 extends Enum {
+    implicit val codec: Codec.AsObject[Enum1.type] = circe.derivation.deriveCodec[Enum1.type]
+  }
+  case object Enum2 extends Enum {
+    implicit val codec: Codec.AsObject[Enum2.type] = circe.derivation.deriveCodec[Enum2.type]
+  }
+}
+
diff --git a/fundamentals/fundamentals-reflection/src/test/scala/izumi.fundamentals.reflection.test/LightTypeTagTest.scala b/fundamentals/fundamentals-reflection/src/test/scala/izumi.fundamentals.reflection.test/LightTypeTagTest.scala
index 81ece7a01..c33d5b0b9 100644
--- a/fundamentals/fundamentals-reflection/src/test/scala/izumi.fundamentals.reflection.test/LightTypeTagTest.scala
+++ b/fundamentals/fundamentals-reflection/src/test/scala/izumi.fundamentals.reflection.test/LightTypeTagTest.scala
@@ -2,13 +2,10 @@ package izumi.fundamentals.reflection.test
 
 import izumi.fundamentals.platform.language.Quirks._
 import izumi.fundamentals.reflection.macrortti._
-import org.scalatest.exceptions.TestFailedException
 
 import scala.collection.immutable.ListSet
 import scala.collection.{BitSet, immutable, mutable}
 
-
-
 class LightTypeTagTest extends TagAssertions {
   import TestModel._
 
diff --git a/fundamentals/fundamentals-reflection/src/test/scala/izumi.fundamentals.reflection.test/TagTest.scala b/fundamentals/fundamentals-reflection/src/test/scala/izumi.fundamentals.reflection.test/TagTest.scala
index 43bb82974..d833801ca 100644
--- a/fundamentals/fundamentals-reflection/src/test/scala/izumi.fundamentals.reflection.test/TagTest.scala
+++ b/fundamentals/fundamentals-reflection/src/test/scala/izumi.fundamentals.reflection.test/TagTest.scala
@@ -223,9 +223,9 @@ class TagTest extends AnyWordSpec with XY[String] {
     }
 
     "Tag.auto.T kind inference macro works for known cases" in {
-      def x[T[_] : Tag.auto.T]: TagK[T] = implicitly[Tag.auto.T[T]]
+      def x[T[_]: Tag.auto.T]: TagK[T] = implicitly[Tag.auto.T[T]]
 
-      def x2[T[_, _] : Tag.auto.T]: TagKK[T] = implicitly[Tag.auto.T[T]]
+      def x2[T[_, _]: Tag.auto.T]: TagKK[T] = implicitly[Tag.auto.T[T]]
 
       def x3[T[_, _, _[_[_], _], _[_], _]](implicit x: Tag.auto.T[T]): Tag.auto.T[T] = x
 
@@ -241,7 +241,7 @@ class TagTest extends AnyWordSpec with XY[String] {
     }
 
     "Work for an abstract type with available TagKK" in {
-      def t1[F[_, _] : TagKK, T: Tag, G: Tag] = Tag[F[T, G]]
+      def t1[F[_, _]: TagKK, T: Tag, G: Tag] = Tag[F[T, G]]
 
       assert(t1[ZOBA[Int, ?, ?], Int, String].tag == fromRuntime[ZOBA[Int, Int, String]])
     }
@@ -249,7 +249,7 @@ class TagTest extends AnyWordSpec with XY[String] {
     "Handle Tags outside of a predefined set" in {
       type TagX[T[_, _, _[_[_], _], _[_], _]] = HKTag[ {type Arg[A, B, C[_[_], _], D[_], E] = T[A, B, C, D, E]}]
 
-      def testTagX[F[_, _, _[_[_], _], _[_], _] : TagX, A: Tag, B: Tag, C[_[_], _] : TagTK, D[_] : TagK, E: Tag] = Tag[F[A, B, C, D, E]]
+      def testTagX[F[_, _, _[_[_], _], _[_], _]: TagX, A: Tag, B: Tag, C[_[_], _]: TagTK, D[_]: TagK, E: Tag] = Tag[F[A, B, C, D, E]]
 
       val value = testTagX[T2, Int, String, OptionT, List, Boolean]
       assert(value.tag == fromRuntime[T2[Int, String, OptionT, List, Boolean]])
@@ -265,14 +265,14 @@ class TagTest extends AnyWordSpec with XY[String] {
 
     "Work for any configuration of parameters" in {
 
-      def t1[A: Tag, B: Tag, C: Tag, D: Tag, E: Tag, F[_] : TagK]: Tag[T1[A, B, C, D, E, F]] = Tag[T1[A, B, C, D, E, F]]
+      def t1[A: Tag, B: Tag, C: Tag, D: Tag, E: Tag, F[_]: TagK]: Tag[T1[A, B, C, D, E, F]] = Tag[T1[A, B, C, D, E, F]]
 
       type ZOB[A, B, C] = Either[B, C]
 
       assert(t1[Int, Boolean, ZOB[Unit, Int, Int], TagK[Option], Nothing, ZOB[Unit, Int, ?]].tag
         == fromRuntime[T1[Int, Boolean, Either[Int, Int], TagK[Option], Nothing, Either[Int, ?]]])
 
-      def t2[A: Tag, dafg: Tag, adfg: Tag, LS: Tag, L[_] : TagK, SD: Tag, GG[A] <: L[A] : TagK, ZZZ[_, _] : TagKK, S: Tag, SDD: Tag, TG: Tag]: Tag[Test[A, dafg, adfg, LS, L, SD, GG, ZZZ, S, SDD, TG]] =
+      def t2[A: Tag, dafg: Tag, adfg: Tag, LS: Tag, L[_]: TagK, SD: Tag, GG[A] <: L[A]: TagK, ZZZ[_, _]: TagKK, S: Tag, SDD: Tag, TG: Tag]: Tag[Test[A, dafg, adfg, LS, L, SD, GG, ZZZ, S, SDD, TG]] =
         Tag[Test[A, dafg, adfg, LS, L, SD, GG, ZZZ, S, SDD, TG]]
 
       assert(t2[TagTest.this.Z, TagTest.this.Z, T1[ZOB[String, Int, Byte], String, String, String, String, List], TagTest.this.Z, XY, TagTest.this.Z, YX, Either, TagTest.this.Z, TagTest.this.Z, TagTest.this.Z].tag
@@ -280,7 +280,7 @@ class TagTest extends AnyWordSpec with XY[String] {
     }
 
     "handle Swap type lambda" in {
-      def t1[F[_, _] : TagKK, A: Tag, B: Tag] = Tag[F[A, B]]
+      def t1[F[_, _]: TagKK, A: Tag, B: Tag] = Tag[F[A, B]]
 
       assert(t1[Swap, Int, String].tag == fromRuntime[Either[String, Int]])
     }
@@ -296,7 +296,7 @@ class TagTest extends AnyWordSpec with XY[String] {
     }
 
     "Assemble from higher than TagKK tags" in {
-      def tag[T[_[_], _] : TagTK, F[_] : TagK, A: Tag] = Tag[T[F, A]]
+      def tag[T[_[_], _]: TagTK, F[_]: TagK, A: Tag] = Tag[T[F, A]]
 
       assert(tag[OptionT, Option, Int].tag == fromRuntime[OptionT[Option, Int]])
     }
diff --git a/logstage/logstage-core/.jvm/src/test/scala/izumi/logstage/ImplicitsTest.scala b/logstage/logstage-core/.jvm/src/test/scala/izumi/logstage/ImplicitsTest.scala
index 3d81b2a25..f23774128 100644
--- a/logstage/logstage-core/.jvm/src/test/scala/izumi/logstage/ImplicitsTest.scala
+++ b/logstage/logstage-core/.jvm/src/test/scala/izumi/logstage/ImplicitsTest.scala
@@ -16,7 +16,7 @@ class ImplicitsTest extends AnyWordSpec {
     val log: LogIO[cats.effect.IO] = LogIO.fromLogger(IzLogger())
     log.discard()
 
-    def logIO[F[_] : Sync]: LogIO[F] = LogIO.fromLogger(IzLogger())
+    def logIO[F[_]: Sync]: LogIO[F] = LogIO.fromLogger(IzLogger())
 
     logIO[cats.effect.IO]
   }
@@ -38,11 +38,11 @@ class ImplicitsTest extends AnyWordSpec {
     val log: LogBIO[zio.IO] = LogBIO.fromLogger(IzLogger())
     log.discard()
 
-    def logIO[F[+ _, + _] : BIO]: LogBIO[F] = LogIO.fromLogger(IzLogger())
+    def logIO[F[+ _, + _]: BIO]: LogBIO[F] = LogIO.fromLogger(IzLogger())
 
     logIO[zio.IO]
 
-    def logBIO[F[+ _, + _] : BIO]: LogBIO[F] = LogBIO.fromLogger(IzLogger())
+    def logBIO[F[+ _, + _]: BIO]: LogBIO[F] = LogBIO.fromLogger(IzLogger())
 
     logBIO[zio.IO]
   }
@@ -75,7 +75,7 @@ class ImplicitsTest extends AnyWordSpec {
       """)
   }
 
-  def logIO[F[_] : LogIO](): F[Unit] = LogIO[F].info("abc")
+  def logIO[F[_]: LogIO](): F[Unit] = LogIO[F].info("abc")
 
   def logThrowable[F[+ _, _]]()(implicit f: LogIO[F[Throwable, ?]]): F[Throwable, Unit] = f.info("cba")