From b484d7e77e826ca556fea8f3daf62ed9e7cca66d Mon Sep 17 00:00:00 2001 From: Jinwoo-H Date: Sun, 16 Aug 2026 23:35:26 -0400 Subject: [PATCH] fix(orchestration): neutralize rejected control messages --- src/main/runtime/orchestration/db.ts | 8 ++++++-- .../rpc/methods/orchestration-send.test.ts | 20 ++++++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/main/runtime/orchestration/db.ts b/src/main/runtime/orchestration/db.ts index 545397faf46..60eafd9cd8f 100644 --- a/src/main/runtime/orchestration/db.ts +++ b/src/main/runtime/orchestration/db.ts @@ -3737,7 +3737,10 @@ export class OrchestrationDb { reason: string ): MessageRow | undefined { const message = this.getMessageById(messageId) - if (!message || (message.type !== 'worker_done' && message.type !== 'heartbeat')) { + if ( + !message || + !['worker_done', 'heartbeat', 'escalation', 'decision_gate'].includes(message.type) + ) { return message } @@ -3748,7 +3751,8 @@ export class OrchestrationDb { this.db .prepare( `UPDATE messages - SET priority = 'high', subject = ?, body = ?, payload = ? + SET type = CASE WHEN type IN ('escalation', 'decision_gate') THEN 'status' ELSE type END, + priority = 'high', subject = ?, body = ?, payload = ? WHERE id = ?` ) .run(`Rejected ${message.type}: ${message.subject}`, body, payload, messageId) diff --git a/src/main/runtime/rpc/methods/orchestration-send.test.ts b/src/main/runtime/rpc/methods/orchestration-send.test.ts index 7b3ed47b38e..1169e7b4e1c 100644 --- a/src/main/runtime/rpc/methods/orchestration-send.test.ts +++ b/src/main/runtime/rpc/methods/orchestration-send.test.ts @@ -279,7 +279,10 @@ describe('orchestration RPC methods', () => { taskId: task.id, ...(type === 'decision_gate' ? { question: 'Proceed?' } : {}) }) - })) as { lifecycle: { action: string; code: string } } + })) as { + lifecycle: { action: string; code: string } + message: { type: string } + } expect(rejected.lifecycle).toMatchObject({ action: 'rejected', @@ -288,6 +291,21 @@ describe('orchestration RPC methods', () => { expect(db.getTask(task.id)?.status).toBe('dispatched') expect(db.getDispatchContextById(dispatch.id)?.status).toBe('dispatched') expect(db.listGates({ taskId: task.id })).toHaveLength(0) + expect(rejected.message.type).toBe('status') + + vi.mocked(runtime.getTerminalProcessIncarnation).mockReturnValue( + 'runtime_test:term_worker:1' + ) + const accepted = (await call('orchestration.send', { + from: 'term_worker', + subject: `${type} by assignee`, + type, + payload: JSON.stringify({ + taskId: task.id, + ...(type === 'decision_gate' ? { question: 'Proceed?' } : {}) + }) + })) as { message: { type: string } } + expect(accepted.message.type).toBe(type) } )