refactor(cleanup-05): remove flat approval/status fields from SessionSnapshot

This commit is contained in:
2026-05-25 16:30:21 +04:00
parent 9dcf6f4c04
commit 9ff58b36ad
6 changed files with 18 additions and 77 deletions
@@ -35,20 +35,8 @@ class SessionEventBridge(
?.map { ApprovalDto(requestId = it.id.value, tier = it.tier.name) } ?.map { ApprovalDto(requestId = it.id.value, tier = it.tier.name) }
?: emptyList() ?: emptyList()
val pendingRequest = approvalState?.requests?.values
?.firstOrNull { req -> approvalState.decisions.values.none { it.requestId == req.id } }
send(ServerMessage.SessionSnapshot( send(ServerMessage.SessionSnapshot(
sessionId = sessionId, sessionId = sessionId,
workflowId = orchState.workflowId,
status = orchState.status.name,
currentStageId = orchState.currentStageId?.value,
pauseReason = orchState.pauseReason,
pendingApproval = orchState.pendingApproval,
approvalRequestId = pendingRequest?.id?.value,
approvalTier = pendingRequest?.tier?.name,
approvalToolName = pendingRequest?.toolName,
approvalPreview = pendingRequest?.preview,
state = SessionStateDto( state = SessionStateDto(
status = orchState.status.name, status = orchState.status.name,
currentStageId = orchState.currentStageId?.value, currentStageId = orchState.currentStageId?.value,
@@ -76,15 +76,6 @@ sealed interface ServerMessage {
@SerialName("session_snapshot") @SerialName("session_snapshot")
data class SessionSnapshot( data class SessionSnapshot(
val sessionId: SessionId, val sessionId: SessionId,
val workflowId: String,
val status: String,
val currentStageId: String?,
val pauseReason: String?,
val pendingApproval: Boolean,
val approvalRequestId: String?,
val approvalTier: String?,
val approvalToolName: String?,
val approvalPreview: String?,
val state: SessionStateDto, val state: SessionStateDto,
val pendingApprovals: List<ApprovalDto>, val pendingApprovals: List<ApprovalDto>,
val lastSequence: Long, val lastSequence: Long,
@@ -39,15 +39,6 @@ class ServerMessageSerializationTest {
fun `SessionSnapshot encodes lastSequence and lastSessionSequence`() { fun `SessionSnapshot encodes lastSequence and lastSessionSequence`() {
val msg = ServerMessage.SessionSnapshot( val msg = ServerMessage.SessionSnapshot(
sessionId = SessionId("sess-1"), sessionId = SessionId("sess-1"),
workflowId = "wf-1",
status = "running",
currentStageId = "stage-1",
pauseReason = null,
pendingApproval = false,
approvalRequestId = null,
approvalTier = null,
approvalToolName = null,
approvalPreview = null,
state = SessionStateDto( state = SessionStateDto(
status = "running", status = "running",
currentStageId = "stage-1", currentStageId = "stage-1",
@@ -117,28 +117,26 @@ object SessionsReducer {
sessionState: SessionsState, sessionState: SessionsState,
msg: ServerMessage.SessionSnapshot, msg: ServerMessage.SessionSnapshot,
): Pair<SessionsState, List<Effect>> { ): Pair<SessionsState, List<Effect>> {
val approvalRequestId = msg.approvalRequestId val firstPending = msg.pendingApprovals.firstOrNull()
val approvalInfo = if (msg.pendingApproval && approvalRequestId != null) { val approvalInfo = firstPending?.let {
ApprovalInfo( ApprovalInfo(
requestId = approvalRequestId, requestId = it.requestId,
sessionId = msg.sessionId.value, sessionId = msg.sessionId.value,
tier = msg.approvalTier ?: "T2", tier = it.tier,
riskSummary = "unknown", riskSummary = "unknown",
toolName = msg.approvalToolName, toolName = null,
preview = msg.approvalPreview, preview = null,
) )
} else null }
val status = if (firstPending != null) "PAUSED awaiting approval" else msg.state.status
val summary = SessionSummary( val summary = SessionSummary(
id = msg.sessionId.value, id = msg.sessionId.value,
status = when { status = status,
msg.pendingApproval -> "PAUSED awaiting approval" workflowId = msg.sessionId.value,
else -> msg.status name = msg.sessionId.value,
},
workflowId = msg.workflowId,
name = msg.workflowId,
lastEventAt = clock(), lastEventAt = clock(),
currentStage = msg.currentStageId, currentStage = msg.state.currentStageId,
currentStageId = msg.currentStageId, currentStageId = msg.state.currentStageId,
pendingApproval = approvalInfo, pendingApproval = approvalInfo,
) )
val selected = sessionState.selectedId ?: msg.sessionId.value val selected = sessionState.selectedId ?: msg.sessionId.value
@@ -290,42 +290,24 @@ class SessionsReducerTest {
} }
@Test @Test
fun `SessionSnapshot with pendingApproval populates pendingApproval on summary`() { fun `SessionSnapshot with pendingApprovals populates pendingApproval on summary`() {
val msg = ServerMessage.SessionSnapshot( val msg = ServerMessage.SessionSnapshot(
sessionId = SessionId("s1"), sessionId = SessionId("s1"),
workflowId = "wf",
status = "PAUSED",
currentStageId = null,
pauseReason = null,
pendingApproval = true,
approvalRequestId = "r9",
approvalTier = "T2",
approvalToolName = "bash",
approvalPreview = "preview text",
state = com.correx.apps.server.protocol.SessionStateDto("PAUSED", null, null), state = com.correx.apps.server.protocol.SessionStateDto("PAUSED", null, null),
pendingApprovals = emptyList(), pendingApprovals = listOf(com.correx.apps.server.protocol.ApprovalDto(requestId = "r9", tier = "T2")),
lastSequence = 1L, lastSequence = 1L,
lastSessionSequence = 1L, lastSessionSequence = 1L,
) )
val (state, _) = reduce(action = Action.ServerEventReceived(msg)) val (state, _) = reduce(action = Action.ServerEventReceived(msg))
assertEquals("r9", state.sessions[0].pendingApproval?.requestId) assertEquals("r9", state.sessions[0].pendingApproval?.requestId)
assertEquals("bash", state.sessions[0].pendingApproval?.toolName) assertEquals("PAUSED awaiting approval", state.sessions[0].status)
} }
@Test @Test
fun `SessionSnapshot without pendingApproval leaves pendingApproval null`() { fun `SessionSnapshot without pendingApprovals leaves pendingApproval null`() {
val msg = ServerMessage.SessionSnapshot( val msg = ServerMessage.SessionSnapshot(
sessionId = SessionId("s1"), sessionId = SessionId("s1"),
workflowId = "wf", state = com.correx.apps.server.protocol.SessionStateDto("ACTIVE", null, null),
status = "ACTIVE",
currentStageId = null,
pauseReason = null,
pendingApproval = false,
approvalRequestId = null,
approvalTier = null,
approvalToolName = null,
approvalPreview = null,
state = com.correx.apps.server.protocol.SessionStateDto("PAUSED", null, null),
pendingApprovals = emptyList(), pendingApprovals = emptyList(),
lastSequence = 1L, lastSequence = 1L,
lastSessionSequence = 1L, lastSessionSequence = 1L,
@@ -108,15 +108,6 @@ class SnapshotPhaseReducerTest {
val state = TuiState(snapshotPhase = true) val state = TuiState(snapshotPhase = true)
val snapshot = ServerMessage.SessionSnapshot( val snapshot = ServerMessage.SessionSnapshot(
sessionId = SessionId("s1"), sessionId = SessionId("s1"),
workflowId = "wf",
status = "ACTIVE",
currentStageId = null,
pauseReason = null,
pendingApproval = false,
approvalRequestId = null,
approvalTier = null,
approvalToolName = null,
approvalPreview = null,
state = SessionStateDto(status = "ACTIVE", currentStageId = null, pauseReason = null), state = SessionStateDto(status = "ACTIVE", currentStageId = null, pauseReason = null),
pendingApprovals = emptyList(), pendingApprovals = emptyList(),
lastSequence = 1L, lastSequence = 1L,