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
+9
View File
@@ -0,0 +1,9 @@
plugins {
id 'java-library'
id 'org.jetbrains.kotlin.jvm'
id 'org.jetbrains.kotlin.plugin.serialization'
}
dependencies {
implementation(project(":core:events"))
}
@@ -0,0 +1,24 @@
package com.correx.core.artifacts
import com.correx.core.events.events.StoredEvent
import com.correx.core.sessions.projections.Projection
import java.util.logging.Logger
class ArtifactProjector(private val reducer: ArtifactReducer) : Projection<ArtifactState> {
private val logger: Logger = Logger.getLogger(ArtifactProjector::class.java.name)
override fun initial(): ArtifactState = ArtifactState()
// Invalid lifecycle transitions must not crash the replayer. Log and leave state unchanged
// so replay continues; the event log remains the source of truth.
override fun apply(state: ArtifactState, event: StoredEvent): ArtifactState =
reducer.reduce(state, event).getOrElse { exception ->
if (exception !is IllegalStateException) throw exception
logger.warning(
"Invalid artifact lifecycle transition (event payload=${event.payload::class.simpleName}): " +
"${exception.message}. State unchanged."
)
state
}
}
@@ -0,0 +1,77 @@
package com.correx.core.artifacts
import com.correx.core.artifacts.model.ArtifactRelationship
import com.correx.core.events.events.ArtifactArchivedEvent
import com.correx.core.events.events.ArtifactCreatedEvent
import com.correx.core.events.events.ArtifactRejectedEvent
import com.correx.core.events.events.ArtifactRelationshipAddedEvent
import com.correx.core.events.events.ArtifactSupersededEvent
import com.correx.core.events.events.ArtifactValidatedEvent
import com.correx.core.events.events.ArtifactValidatingEvent
import com.correx.core.events.events.StoredEvent
import com.correx.core.events.types.ArtifactLifecyclePhase
interface ArtifactReducer {
fun reduce(state: ArtifactState, event: StoredEvent): Result<ArtifactState>
}
class DefaultArtifactReducer : ArtifactReducer {
override fun reduce(state: ArtifactState, event: StoredEvent): Result<ArtifactState> =
when (val p = event.payload) {
is ArtifactCreatedEvent ->
Result.success(state.copy(phase = ArtifactLifecyclePhase.CREATED))
is ArtifactValidatingEvent ->
transition(state, ArtifactLifecyclePhase.VALIDATING, ArtifactLifecyclePhase.CREATED)
is ArtifactValidatedEvent ->
transition(state, ArtifactLifecyclePhase.VALIDATED, ArtifactLifecyclePhase.VALIDATING)
is ArtifactRejectedEvent ->
transition(state, ArtifactLifecyclePhase.REJECTED, ArtifactLifecyclePhase.VALIDATING)
is ArtifactSupersededEvent ->
transition(state, ArtifactLifecyclePhase.SUPERSEDED, ArtifactLifecyclePhase.VALIDATED)
is ArtifactArchivedEvent ->
transitionFromAny(
state,
ArtifactLifecyclePhase.ARCHIVED,
ArtifactLifecyclePhase.VALIDATED,
ArtifactLifecyclePhase.REJECTED,
)
is ArtifactRelationshipAddedEvent -> {
val rel = ArtifactRelationship(p.sourceId, p.targetId, p.relationshipType)
Result.success(
state.copy(lineage = state.lineage.copy(relationships = state.lineage.relationships + rel))
)
}
else -> Result.success(state)
}
private fun transition(
state: ArtifactState,
to: ArtifactLifecyclePhase,
from: ArtifactLifecyclePhase,
): Result<ArtifactState> =
if (state.phase == from) {
Result.success(state.copy(phase = to))
} else {
Result.failure(
IllegalStateException(
"Invalid artifact transition: ${state.phase}$to (expected $from)"
)
)
}
private fun transitionFromAny(
state: ArtifactState,
to: ArtifactLifecyclePhase,
vararg validFrom: ArtifactLifecyclePhase,
): Result<ArtifactState> =
if (state.phase in validFrom) {
Result.success(state.copy(phase = to))
} else {
Result.failure(
IllegalStateException(
"Invalid artifact transition: ${state.phase}$to (expected one of ${validFrom.toList()})"
)
)
}
}
@@ -0,0 +1,11 @@
package com.correx.core.artifacts
import com.correx.core.artifacts.model.ArtifactLineage
import com.correx.core.events.types.ArtifactLifecyclePhase
import kotlinx.serialization.Serializable
@Serializable
data class ArtifactState(
val phase: ArtifactLifecyclePhase = ArtifactLifecyclePhase.CREATED,
val lineage: ArtifactLineage = ArtifactLineage()
)
@@ -0,0 +1,3 @@
package com.correx.core.artifacts
object Module
@@ -0,0 +1,20 @@
package com.correx.core.artifacts.model
import com.correx.core.events.types.ArtifactId
import com.correx.core.events.types.ArtifactLifecyclePhase
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
@Serializable
sealed interface Artifact {
val id: ArtifactId
val sessionId: SessionId
val stageId: StageId
val schemaVersion: Int
val createdAt: Instant
val lifecyclePhase: ArtifactLifecyclePhase
val lineage: ArtifactLineage
val metadata: Map<String, String>
}
@@ -0,0 +1,12 @@
package com.correx.core.artifacts.model
import com.correx.core.events.types.ArtifactId
import com.correx.core.events.types.ValidationReportId
import kotlinx.serialization.Serializable
@Serializable
data class ArtifactLineage(
val parentIds: List<ArtifactId> = emptyList(),
val relationships: List<ArtifactRelationship> = emptyList(),
val validationReportIds: List<ValidationReportId> = emptyList()
)
@@ -0,0 +1,12 @@
package com.correx.core.artifacts.model
import com.correx.core.events.types.ArtifactId
import com.correx.core.events.types.ArtifactRelationshipType
import kotlinx.serialization.Serializable
@Serializable
data class ArtifactRelationship(
val sourceId: ArtifactId,
val targetId: ArtifactId,
val type: ArtifactRelationshipType
)
@@ -0,0 +1,11 @@
package com.correx.core.artifacts.serialization
import com.correx.core.artifacts.model.Artifact
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic
val artifactModule: SerializersModule = SerializersModule {
polymorphic(Artifact::class) {
// concrete artifact subclasses registered here in future epics
}
}