feat(workflow): ExecutionPlanCompiler + ExecutionPlanLockedEvent (Slice 3)
- ExecutionPlanLockedEvent: registered, replay-deterministic record of the locked plan (CAS ref + compiled stage/start ids). - ExecutionPlanCompiler: validated execution_plan JSON -> WorkflowGraph, reusing ConditionSpec.toCondition(); inline prompts via metadata[promptInline]; malformed plans throw WorkflowValidationException. - Replay test: locked event + plan JSON recompiles to the identical graph, no architect re-run, no FS reads.
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
package com.correx.core.events.events
|
||||
|
||||
import com.correx.core.events.types.ArtifactId
|
||||
import com.correx.core.events.types.SessionId
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* The architect's validated execution_plan was compiled into a runnable WorkflowGraph and
|
||||
* locked as the baseline for phase 2. [planArtifactId] points at the validated plan JSON in
|
||||
* CAS (referenced, not inlined); [stageIds]/[startStageId] pin the compiled shape so replay
|
||||
* rebuilds the identical graph. Soft lock: later high-priority steering can still preempt.
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("ExecutionPlanLocked")
|
||||
data class ExecutionPlanLockedEvent(
|
||||
val sessionId: SessionId,
|
||||
val planArtifactId: ArtifactId,
|
||||
val workflowId: String,
|
||||
val stageIds: List<String>,
|
||||
val startStageId: String,
|
||||
) : EventPayload
|
||||
@@ -13,6 +13,7 @@ import com.correx.core.events.events.RouterNarrationEvent
|
||||
import com.correx.core.events.events.SessionWorkspaceBoundEvent
|
||||
import com.correx.core.events.events.ContextTruncatedEvent
|
||||
import com.correx.core.events.events.EventPayload
|
||||
import com.correx.core.events.events.ExecutionPlanLockedEvent
|
||||
import com.correx.core.events.events.FileWrittenEvent
|
||||
import com.correx.core.events.events.L3MemoryRetrievedEvent
|
||||
import com.correx.core.events.events.InferenceCompletedEvent
|
||||
@@ -91,6 +92,7 @@ val eventModule = SerializersModule {
|
||||
subclass(SessionWorkspaceBoundEvent::class)
|
||||
subclass(L3MemoryRetrievedEvent::class)
|
||||
subclass(ContextTruncatedEvent::class)
|
||||
subclass(ExecutionPlanLockedEvent::class)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.correx.core.events.serialization
|
||||
|
||||
import com.correx.core.events.events.EventPayload
|
||||
import com.correx.core.events.events.ExecutionPlanLockedEvent
|
||||
import com.correx.core.events.types.ArtifactId
|
||||
import com.correx.core.events.types.SessionId
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class ExecutionPlanLockedEventSerializationTest {
|
||||
|
||||
@Test
|
||||
fun `ExecutionPlanLockedEvent round-trips as polymorphic EventPayload`() {
|
||||
val sample: EventPayload = ExecutionPlanLockedEvent(
|
||||
sessionId = SessionId("s"),
|
||||
planArtifactId = ArtifactId("execution_plan"),
|
||||
workflowId = "freestyle-s",
|
||||
stageIds = listOf("impl", "review"),
|
||||
startStageId = "impl",
|
||||
)
|
||||
val encoded = eventJson.encodeToString(EventPayload.serializer(), sample)
|
||||
assertTrue(encoded.contains("\"type\":\"ExecutionPlanLocked\""), "SerialName must be present: $encoded")
|
||||
val decoded = eventJson.decodeFromString(EventPayload.serializer(), encoded)
|
||||
assertEquals(sample, decoded)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user