From 9924e447c8a7f6f3a218eaa529ecac8fd457d7aa Mon Sep 17 00:00:00 2001 From: 777genius Date: Sun, 31 May 2026 09:31:26 +0300 Subject: [PATCH] fix(team): treat stale observe refresh marker as recoverable --- .../delivery/OpenCodePromptDeliveryLedger.ts | 1 + .../OpenCodeRuntimeDeliveryDiagnostics.ts | 1 + .../runtime/RuntimeDiagnosticClassifier.ts | 3 ++- ...OpenCodeRuntimeDeliveryDiagnostics.test.ts | 19 +++++++++++++++++++ .../team/RuntimeDiagnosticClassifier.test.ts | 10 ++++++++++ .../TeamMemberRuntimeAdvisoryService.test.ts | 5 +---- 6 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/main/services/team/opencode/delivery/OpenCodePromptDeliveryLedger.ts b/src/main/services/team/opencode/delivery/OpenCodePromptDeliveryLedger.ts index 39376c22..1f501ae1 100644 --- a/src/main/services/team/opencode/delivery/OpenCodePromptDeliveryLedger.ts +++ b/src/main/services/team/opencode/delivery/OpenCodePromptDeliveryLedger.ts @@ -976,6 +976,7 @@ function isOpenCodeSessionRefreshScheduledReason(message: string | null | undefi normalized === 'opencode_prompt_delivery_session_refresh_scheduled' || normalized === 'opencode session refresh scheduled after resolved behavior changed' || normalized === 'opencode_session_refresh_scheduled_after_resolved_behavior_changed' || + normalized === 'opencode_session_stale_observe_scheduled_after_accepted_prompt' || normalized === 'opencode session changed; refreshing the session before retry' ); } diff --git a/src/main/services/team/opencode/delivery/OpenCodeRuntimeDeliveryDiagnostics.ts b/src/main/services/team/opencode/delivery/OpenCodeRuntimeDeliveryDiagnostics.ts index 6458b8ac..10f0a0f9 100644 --- a/src/main/services/team/opencode/delivery/OpenCodeRuntimeDeliveryDiagnostics.ts +++ b/src/main/services/team/opencode/delivery/OpenCodeRuntimeDeliveryDiagnostics.ts @@ -61,6 +61,7 @@ function isOpenCodeRuntimeDeliverySessionRefreshScheduledDiagnostic(message: str normalized === 'opencode_prompt_delivery_session_refresh_scheduled' || normalized === 'opencode session refresh scheduled after resolved behavior changed' || normalized === 'opencode_session_refresh_scheduled_after_resolved_behavior_changed' || + normalized === 'opencode_session_stale_observe_scheduled_after_accepted_prompt' || normalized === 'opencode session changed; refreshing the session before retry' ); } diff --git a/src/main/services/team/runtime/RuntimeDiagnosticClassifier.ts b/src/main/services/team/runtime/RuntimeDiagnosticClassifier.ts index 930faeec..4a1c43a8 100644 --- a/src/main/services/team/runtime/RuntimeDiagnosticClassifier.ts +++ b/src/main/services/team/runtime/RuntimeDiagnosticClassifier.ts @@ -49,7 +49,8 @@ function isCleanOpenCodeSessionRefreshDiagnostic(message: string): boolean { refreshMarkerText === 'opencode session changed; refreshing the session before retry' || refreshMarkerText === 'opencode session refresh scheduled after resolved behavior changed' || refreshMarkerText === 'opencode_prompt_delivery_session_refresh_scheduled' || - refreshMarkerText === 'opencode_session_refresh_scheduled_after_resolved_behavior_changed' + refreshMarkerText === 'opencode_session_refresh_scheduled_after_resolved_behavior_changed' || + refreshMarkerText === 'opencode_session_stale_observe_scheduled_after_accepted_prompt' ) { return true; } diff --git a/test/main/services/team/OpenCodeRuntimeDeliveryDiagnostics.test.ts b/test/main/services/team/OpenCodeRuntimeDeliveryDiagnostics.test.ts index 6b1962e9..c8a26875 100644 --- a/test/main/services/team/OpenCodeRuntimeDeliveryDiagnostics.test.ts +++ b/test/main/services/team/OpenCodeRuntimeDeliveryDiagnostics.test.ts @@ -163,6 +163,25 @@ describe('OpenCodeRuntimeDeliveryDiagnostics', () => { ); }); + it('treats stale observe scheduled diagnostics after an accepted prompt as session refresh', () => { + const record = { + diagnostics: [ + 'OpenCode API error', + 'OpenCode API error. opencode_session_stale_observe_scheduled_after_accepted_prompt', + ], + lastReason: 'OpenCode API error', + responseState: 'not_observed', + status: 'retry_scheduled', + } as Parameters[0]; + + expect(selectOpenCodeRuntimeDeliveryReason(record)).toBe( + 'OpenCode session changed; refreshing the session before retry.' + ); + expect( + isActionRequiredOpenCodeRuntimeDeliveryReason(selectOpenCodeRuntimeDeliveryReason(record)) + ).toBe(false); + }); + it('treats colon-terminated generic OpenCode API errors plus clean refresh evidence as session refresh', () => { const record = { diagnostics: ['OpenCode API error:', 'resolved_behavior_changed:old->new'], diff --git a/test/main/services/team/RuntimeDiagnosticClassifier.test.ts b/test/main/services/team/RuntimeDiagnosticClassifier.test.ts index 09e5e2c8..6e8cc6bf 100644 --- a/test/main/services/team/RuntimeDiagnosticClassifier.test.ts +++ b/test/main/services/team/RuntimeDiagnosticClassifier.test.ts @@ -228,6 +228,16 @@ describe('RuntimeDiagnosticClassifier', () => { generic: true, actionRequired: false, }); + expect( + classifyRuntimeDiagnostic( + 'OpenCode API error. opencode_session_stale_observe_scheduled_after_accepted_prompt' + ) + ).toMatchObject({ + reasonCode: 'backend_error', + normalizedMessage: 'OpenCode session changed; refreshing the session before retry.', + generic: true, + actionRequired: false, + }); }); it('does not classify refresh markers with unknown extra text as clean refresh', () => { diff --git a/test/main/services/team/TeamMemberRuntimeAdvisoryService.test.ts b/test/main/services/team/TeamMemberRuntimeAdvisoryService.test.ts index eabcf3b9..a1d896fa 100644 --- a/test/main/services/team/TeamMemberRuntimeAdvisoryService.test.ts +++ b/test/main/services/team/TeamMemberRuntimeAdvisoryService.test.ts @@ -129,7 +129,6 @@ function buildOpenCodeDeliveryRecord( lastReason: 'OpenCode bridge command timed out', diagnostics: [ 'OpenCode prompt_async accepted; response observation will continue through durable app-side ledger reconciliation.', - 'project_behavior_changed', 'opencode_session_stale_observe_scheduled_after_accepted_prompt', 'OpenCode bridge command timed out', ], @@ -762,9 +761,7 @@ describe('TeamMemberRuntimeAdvisoryService', () => { kind: 'api_error', reasonCode: 'backend_error', }); - expect(advisory?.message).toContain( - 'opencode_session_stale_observe_scheduled_after_accepted_prompt' - ); + expect(advisory?.message).toBe('OpenCode runtime delivery did not complete.'); }); it('keeps stale OpenCode advisories visible after unrelated later delivery success', async () => {