fix: P1 TUI UX batch — race root cause, diff content, per-session routerMessages, optimistic IDLE submit
P1-1: Replace check-then-act with computeIfAbsent for activeSessionJobs to prevent double-launch. Register pendingApprovals[requestId] BEFORE emitting ApprovalRequestedEvent to close the approve-before-register window. P1-2: ToolCompleted with a diff now appends msg.diff to routerMessages instead of the static "--- diff from $toolName ---" marker. P1-3: Change routerMessages from List<String> to Map<String, List<String>> keyed by sessionId.value. RootReducer appends to the correct session's list; RouterPanel renders only routerMessages[selectedId]. P1-4: On IDLE chat submit, SessionsReducer creates an optimistic SessionSummary(status="STARTING") and sets selectedId. processSessionStartedMessage removes any STARTING session and inserts the real one on echo. RootReducer sets sessionEntered=true for the optimistic session. Tests: LaunchRegistrationRaceTest, ApprovalRegisterBeforeEmitTest, RootReducerTest (diff/per-session/isolation/optimistic-submit), SessionsReducerTest (optimistic/reconciliation). All P0/P1 tests pass. ./gradlew check green.
This commit is contained in:
+5
-6
@@ -407,6 +407,8 @@ abstract class SessionOrchestrator(
|
||||
}
|
||||
// grant auto-approved — fall through to execute
|
||||
} else {
|
||||
val deferred = CompletableDeferred<ApprovalDecision>()
|
||||
pendingApprovals[requestId] = deferred
|
||||
emit(sessionId, OrchestrationPausedEvent(sessionId, stageId, "APPROVAL_PENDING"))
|
||||
emit(
|
||||
sessionId,
|
||||
@@ -422,8 +424,6 @@ abstract class SessionOrchestrator(
|
||||
preview = toolPreview ?: toolCall.function.arguments.take(200),
|
||||
),
|
||||
)
|
||||
val deferred = CompletableDeferred<ApprovalDecision>()
|
||||
pendingApprovals[requestId] = deferred
|
||||
val userDecision = try {
|
||||
deferred.await()
|
||||
} finally {
|
||||
@@ -830,9 +830,11 @@ abstract class SessionOrchestrator(
|
||||
outcome: ValidationOutcome.NeedsApproval,
|
||||
): StageExecutionResult {
|
||||
log.debug("[Orchestrator] approval required session={} stage={}", sessionId.value, stageId.value)
|
||||
emit(sessionId, OrchestrationPausedEvent(sessionId, stageId, "APPROVAL_PENDING"))
|
||||
val domainRequest = buildApprovalRequest(sessionId, stageId, outcome)
|
||||
val deferred = CompletableDeferred<ApprovalDecision>()
|
||||
pendingApprovals[domainRequest.id] = deferred
|
||||
|
||||
emit(sessionId, OrchestrationPausedEvent(sessionId, stageId, "APPROVAL_PENDING"))
|
||||
emit(
|
||||
sessionId,
|
||||
ApprovalRequestedEvent(
|
||||
@@ -846,9 +848,6 @@ abstract class SessionOrchestrator(
|
||||
),
|
||||
)
|
||||
|
||||
val deferred = CompletableDeferred<ApprovalDecision>()
|
||||
pendingApprovals[domainRequest.id] = deferred
|
||||
|
||||
return try {
|
||||
log.debug(
|
||||
"[Orchestrator] awaiting approval session={} requestId={}",
|
||||
|
||||
Reference in New Issue
Block a user