epic-12: after epic audit and init commit

This commit is contained in:
2026-05-16 11:42:00 +04:00
commit c77277af0b
461 changed files with 28958 additions and 0 deletions
@@ -0,0 +1,38 @@
package com.correx.infrastructure.inference
import com.correx.core.events.types.ProviderId
import com.correx.core.inference.InferenceProvider
import com.correx.core.inference.ModelCapability
import com.correx.core.inference.ProviderHealth
import com.correx.core.inference.ProviderRegistry
import java.util.concurrent.CopyOnWriteArrayList
/**
* In-memory [ProviderRegistry] backed by a [CopyOnWriteArrayList] for safe concurrent reads.
*
* Providers supplied at construction are registered immediately.
* Additional providers may be registered at any time via [register].
*/
class DefaultProviderRegistry(
initialProviders: List<InferenceProvider> = emptyList(),
) : ProviderRegistry {
private val providers: CopyOnWriteArrayList<InferenceProvider> =
CopyOnWriteArrayList(initialProviders)
override fun register(provider: InferenceProvider) {
providers.add(provider)
}
override fun resolve(capability: ModelCapability): List<InferenceProvider> =
providers
.filter { p -> p.capabilities().any { it.capability == capability } }
.sortedByDescending { p ->
p.capabilities().firstOrNull { it.capability == capability }?.score ?: 0.0
}
override fun listAll(): List<InferenceProvider> = providers.toList()
override suspend fun healthCheckAll(): Map<ProviderId, ProviderHealth> =
providers.associate { it.id to it.healthCheck() }
}
@@ -0,0 +1,32 @@
package com.correx.infrastructure.inference
import com.correx.core.inference.InferenceProvider
import com.correx.core.inference.ModelCapability
import com.correx.core.inference.NoEligibleProviderException
import com.correx.core.inference.RoutingStrategy
import com.correx.core.events.types.StageId
/**
* Selects the first [InferenceProvider] from [candidates] whose declared capabilities
* cover all [requiredCapabilities].
*
* "First" means the list order as supplied by [ProviderRegistry.resolve] — callers that
* want score-ordered selection should pass a score-sorted list.
*
* @throws NoEligibleProviderException if no candidate satisfies all required capabilities.
*/
class FirstAvailableRoutingStrategy : RoutingStrategy {
override fun select(
candidates: List<InferenceProvider>,
requiredCapabilities: Set<ModelCapability>,
): InferenceProvider {
val declared = candidates.firstOrNull { provider ->
val providerCapabilities = provider.capabilities().map { it.capability }.toSet()
providerCapabilities.containsAll(requiredCapabilities)
}
return declared ?: throw NoEligibleProviderException(
StageId("routing"),
requiredCapabilities,
)
}
}
@@ -0,0 +1,3 @@
package com.correx.infrastructure.inference
object Module
@@ -0,0 +1,80 @@
package com.correx.infrastructure.inference
import com.correx.core.events.types.ProviderId
import com.correx.core.inference.CapabilityScore
import com.correx.core.inference.InferenceProvider
import com.correx.core.inference.InferenceRequest
import com.correx.core.inference.InferenceResponse
import com.correx.core.inference.ModelCapability
import com.correx.core.inference.ProviderHealth
import com.correx.core.inference.Tokenizer
import com.correx.core.inference.Token
import com.correx.core.utils.TypeId
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
class DefaultProviderRegistryTest {
private fun fakeProvider(
id: String,
vararg caps: Pair<ModelCapability, Double>,
): InferenceProvider = object : InferenceProvider {
override val id: ProviderId = TypeId(id)
override val name: String = id
override val tokenizer: Tokenizer = object : Tokenizer {
override suspend fun tokenize(text: String): List<Token> = emptyList()
override suspend fun countTokens(text: String): Int = 0
}
override suspend fun infer(request: InferenceRequest): InferenceResponse =
error("not implemented in test")
override suspend fun healthCheck(): ProviderHealth = ProviderHealth.Healthy
override fun capabilities(): Set<CapabilityScore> =
caps.map { (cap, score) -> CapabilityScore(cap, score) }.toSet()
}
@Test
fun `listAll returns all registered providers`() {
val p1 = fakeProvider("p1", ModelCapability.Coding to 0.9)
val p2 = fakeProvider("p2", ModelCapability.General to 0.8)
val registry = DefaultProviderRegistry(listOf(p1, p2))
assertEquals(2, registry.listAll().size)
}
@Test
fun `register adds provider`() {
val registry = DefaultProviderRegistry()
val p = fakeProvider("p1", ModelCapability.Coding to 0.9)
registry.register(p)
assertEquals(1, registry.listAll().size)
}
@Test
fun `resolve returns providers with matching capability ordered by score desc`() {
val low = fakeProvider("low", ModelCapability.Coding to 0.5)
val high = fakeProvider("high", ModelCapability.Coding to 0.9)
val other = fakeProvider("other", ModelCapability.General to 0.8)
val registry = DefaultProviderRegistry(listOf(low, high, other))
val resolved = registry.resolve(ModelCapability.Coding)
assertEquals(2, resolved.size)
assertEquals("high", resolved.first().id.value)
}
@Test
fun `resolve returns empty list when no provider matches`() {
val registry = DefaultProviderRegistry(listOf(fakeProvider("p", ModelCapability.General to 1.0)))
assertTrue(registry.resolve(ModelCapability.Reasoning).isEmpty())
}
@Test
fun `healthCheckAll returns health for all providers`() = runTest {
val p1 = fakeProvider("p1", ModelCapability.Coding to 1.0)
val p2 = fakeProvider("p2", ModelCapability.General to 1.0)
val registry = DefaultProviderRegistry(listOf(p1, p2))
val health = registry.healthCheckAll()
assertEquals(2, health.size)
assertTrue(health.values.all { it is ProviderHealth.Healthy })
}
}
@@ -0,0 +1,77 @@
package com.correx.infrastructure.inference
import com.correx.core.events.types.ProviderId
import com.correx.core.inference.CapabilityScore
import com.correx.core.inference.InferenceProvider
import com.correx.core.inference.InferenceRequest
import com.correx.core.inference.InferenceResponse
import com.correx.core.inference.ModelCapability
import com.correx.core.inference.NoEligibleProviderException
import com.correx.core.inference.ProviderHealth
import com.correx.core.inference.Token
import com.correx.core.inference.Tokenizer
import com.correx.core.utils.TypeId
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
class FirstAvailableRoutingStrategyTest {
private val strategy = FirstAvailableRoutingStrategy()
private fun fakeProvider(id: String, vararg caps: ModelCapability): InferenceProvider =
object : InferenceProvider {
override val id: ProviderId = TypeId(id)
override val name: String = id
override val tokenizer: Tokenizer = object : Tokenizer {
override suspend fun tokenize(text: String): List<Token> = emptyList()
override suspend fun countTokens(text: String): Int = 0
}
override suspend fun infer(request: InferenceRequest): InferenceResponse =
error("not implemented in test")
override suspend fun healthCheck(): ProviderHealth = ProviderHealth.Healthy
override fun capabilities(): Set<CapabilityScore> =
caps.map { CapabilityScore(it, 1.0) }.toSet()
}
@Test
fun `selects first provider satisfying all required capabilities`() {
val coding = fakeProvider("codingOnly", ModelCapability.Coding)
val general = fakeProvider("generalAndCoding", ModelCapability.General, ModelCapability.Coding)
val required = setOf(ModelCapability.Coding, ModelCapability.General)
val selected = strategy.select(listOf(coding, general), required)
assertEquals("generalAndCoding", selected.id.value)
}
@Test
fun `selects first matching provider when multiple satisfy requirements`() {
val p1 = fakeProvider("p1", ModelCapability.Coding)
val p2 = fakeProvider("p2", ModelCapability.Coding)
val selected = strategy.select(listOf(p1, p2), setOf(ModelCapability.Coding))
assertEquals("p1", selected.id.value)
}
@Test
fun `throws NoEligibleProviderException when no candidate satisfies required capabilities`() {
val general = fakeProvider("general", ModelCapability.General)
assertThrows<NoEligibleProviderException> {
strategy.select(listOf(general), setOf(ModelCapability.Coding))
}
}
@Test
fun `throws NoEligibleProviderException when candidates list is empty`() {
assertThrows<NoEligibleProviderException> {
strategy.select(emptyList(), setOf(ModelCapability.Coding))
}
}
@Test
fun `selects any provider when required capabilities is empty`() {
val p = fakeProvider("p", ModelCapability.General)
val selected = strategy.select(listOf(p), emptySet())
assertEquals("p", selected.id.value)
}
}