feat(events,sessions): ProjectProfileBoundEvent reduced into session state
This commit is contained in:
@@ -27,3 +27,13 @@ data class OperatorProfileBoundEvent(
|
||||
val preferredModels: List<String>,
|
||||
val conventions: List<String>,
|
||||
) : EventPayload
|
||||
|
||||
@Serializable
|
||||
@SerialName("ProjectProfileBound")
|
||||
data class ProjectProfileBoundEvent(
|
||||
val sessionId: SessionId,
|
||||
val workspaceRoot: String,
|
||||
val about: String,
|
||||
val conventions: List<String>,
|
||||
val commands: Map<String, String>,
|
||||
) : EventPayload
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.correx.core.events.events.ChatSessionStartedEvent
|
||||
import com.correx.core.events.events.ChatTurnEvent
|
||||
import com.correx.core.events.events.RouterNarrationEvent
|
||||
import com.correx.core.events.events.OperatorProfileBoundEvent
|
||||
import com.correx.core.events.events.ProjectProfileBoundEvent
|
||||
import com.correx.core.events.events.SessionWorkspaceBoundEvent
|
||||
import com.correx.core.events.events.ContextTruncatedEvent
|
||||
import com.correx.core.events.events.EventPayload
|
||||
@@ -100,6 +101,7 @@ val eventModule = SerializersModule {
|
||||
subclass(RouterNarrationEvent::class)
|
||||
subclass(SessionWorkspaceBoundEvent::class)
|
||||
subclass(OperatorProfileBoundEvent::class)
|
||||
subclass(ProjectProfileBoundEvent::class)
|
||||
subclass(L3MemoryRetrievedEvent::class)
|
||||
subclass(ContextTruncatedEvent::class)
|
||||
subclass(ExecutionPlanLockedEvent::class)
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.correx.core.events.serialization
|
||||
|
||||
import com.correx.core.events.events.EventPayload
|
||||
import com.correx.core.events.events.ProjectProfileBoundEvent
|
||||
import com.correx.core.events.types.SessionId
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class ProjectProfileBoundEventSerializationTest {
|
||||
|
||||
@Test
|
||||
fun `ProjectProfileBoundEvent round-trips as polymorphic EventPayload`() {
|
||||
val sample: EventPayload = ProjectProfileBoundEvent(
|
||||
sessionId = SessionId("s1"),
|
||||
workspaceRoot = "/repo",
|
||||
about = "Event-sourced orchestration kernel",
|
||||
conventions = listOf("no bare try-catch", "events are the only source of truth"),
|
||||
commands = mapOf("build" to "./gradlew build", "test" to "./gradlew check"),
|
||||
)
|
||||
val encoded = eventJson.encodeToString(EventPayload.serializer(), sample)
|
||||
assertTrue(encoded.contains("\"type\":\"ProjectProfileBound\""), "SerialName must be present: $encoded")
|
||||
val decoded = eventJson.decodeFromString(EventPayload.serializer(), encoded)
|
||||
assertEquals(sample, decoded)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `round-trips with empty fields`() {
|
||||
val sample: EventPayload = ProjectProfileBoundEvent(
|
||||
sessionId = SessionId("s0"),
|
||||
workspaceRoot = "/empty",
|
||||
about = "",
|
||||
conventions = emptyList(),
|
||||
commands = emptyMap(),
|
||||
)
|
||||
val encoded = eventJson.encodeToString(EventPayload.serializer(), sample)
|
||||
val decoded = eventJson.decodeFromString(EventPayload.serializer(), encoded)
|
||||
assertEquals(sample, decoded)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.correx.core.sessions
|
||||
|
||||
data class BoundProjectProfile(
|
||||
val about: String,
|
||||
val conventions: List<String>,
|
||||
val commands: Map<String, String>,
|
||||
)
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.correx.core.sessions
|
||||
|
||||
import com.correx.core.events.events.OperatorProfileBoundEvent
|
||||
import com.correx.core.events.events.ProjectProfileBoundEvent
|
||||
import com.correx.core.events.events.SessionWorkspaceBoundEvent
|
||||
import com.correx.core.events.events.StageCompletedEvent
|
||||
import com.correx.core.events.events.StageFailedEvent
|
||||
@@ -51,12 +52,22 @@ class DefaultSessionReducer : SessionReducer {
|
||||
else -> state.boundProfile
|
||||
}
|
||||
|
||||
val boundProjectProfile = when (payload) {
|
||||
is ProjectProfileBoundEvent -> BoundProjectProfile(
|
||||
about = payload.about,
|
||||
conventions = payload.conventions,
|
||||
commands = payload.commands,
|
||||
)
|
||||
else -> state.boundProjectProfile
|
||||
}
|
||||
|
||||
return state.copy(
|
||||
status = newStatus,
|
||||
createdAt = createdAt,
|
||||
updatedAt = event.metadata.timestamp,
|
||||
boundWorkspace = boundWorkspace,
|
||||
boundProfile = boundProfile,
|
||||
boundProjectProfile = boundProjectProfile,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,4 +9,5 @@ data class SessionState(
|
||||
val invalidTransitions: Int = 0,
|
||||
val boundWorkspace: BoundWorkspace? = null,
|
||||
val boundProfile: BoundProfile? = null,
|
||||
val boundProjectProfile: BoundProjectProfile? = null,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user