feat(recovery,context): tier-2 intent-holder arbiter + remaining-delta pinning + surfaced signal events
- recovery: two-tier repair ladder — owner then arbiter (recovery stage recast
as intent-holder, holds initial intent, reconciles cross-file contract disputes)
with independent INTENT_ROUTE_BUDGET; RecoveryRoutingTest coverage
- context: remaining-delta checklist pinning (RemainingDelta{Pinning,Entry}Test)
- surface write-only events (session name, quality signals) into stats/browse
- parseToolArguments lenient-Json fallback for bare-key drift
- tools: ChildProcess seam
This commit is contained in:
@@ -7,6 +7,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
data class SessionSummary(
|
||||
val sessionId: SessionId,
|
||||
val name: String?,
|
||||
val intent: String?,
|
||||
val workflowId: String?,
|
||||
val status: String,
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.correx.core.sessions
|
||||
|
||||
import com.correx.core.events.events.InitialIntentEvent
|
||||
import com.correx.core.events.events.OrchestrationPausedEvent
|
||||
import com.correx.core.events.events.SessionNamedEvent
|
||||
import com.correx.core.events.events.StoredEvent
|
||||
import com.correx.core.events.events.TransitionExecutedEvent
|
||||
import com.correx.core.events.events.WorkflowCompletedEvent
|
||||
@@ -12,6 +13,7 @@ import com.correx.core.events.types.SessionId
|
||||
class SessionSummaryProjector {
|
||||
fun project(sessionId: SessionId, events: List<StoredEvent>): SessionSummary {
|
||||
var intent: String? = null
|
||||
var name: String? = null
|
||||
var workflowId: String? = null
|
||||
var stageCount = 0
|
||||
var status = "UNKNOWN"
|
||||
@@ -21,6 +23,7 @@ class SessionSummaryProjector {
|
||||
events.forEach { event ->
|
||||
when (val p = event.payload) {
|
||||
is InitialIntentEvent -> intent = p.intent
|
||||
is SessionNamedEvent -> name = p.name
|
||||
is WorkflowStartedEvent -> {
|
||||
workflowId = p.workflowId
|
||||
status = SessionStatus.ACTIVE.name
|
||||
@@ -35,6 +38,7 @@ class SessionSummaryProjector {
|
||||
|
||||
return SessionSummary(
|
||||
sessionId = sessionId,
|
||||
name = name,
|
||||
intent = intent,
|
||||
workflowId = workflowId,
|
||||
status = status,
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.correx.core.sessions
|
||||
|
||||
import com.correx.core.events.events.EventMetadata
|
||||
import com.correx.core.events.events.InitialIntentEvent
|
||||
import com.correx.core.events.events.SessionNamedEvent
|
||||
import com.correx.core.events.events.StoredEvent
|
||||
import com.correx.core.events.events.TransitionExecutedEvent
|
||||
import com.correx.core.events.types.EventId
|
||||
@@ -58,6 +59,15 @@ class SessionSummaryProjectorTest {
|
||||
assertEquals("add auth layer", summary.intent)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `SessionNamedEvent surfaces the human name in the summary`() {
|
||||
val event = stored(SessionNamedEvent(sessionId, "Add auth layer", timestampMs = 0L))
|
||||
|
||||
val summary = projector.project(sessionId, listOf(event))
|
||||
|
||||
assertEquals("Add auth layer", summary.name)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `two TransitionExecutedEvents yield stageCount of two`() {
|
||||
val t1 = stored(
|
||||
|
||||
Reference in New Issue
Block a user