Skip to content

Commit c0195f7

Browse files
openperfsteipete
andauthored
fix(diagnostics): clear embedded-run activity when recovery declares lane idle (#88820)
* fix(diagnostics): clear embedded-run activity when recovery declares lane idle Stuck-session recovery transitions a lane to idle via the recovery coordinator, but only mutated the session-state store. When an aborted embedded run was removed without markDiagnosticEmbeddedRunEnded, the activity store kept hasActiveEmbeddedRun set, so the liveness sweep reported idle/embedded_run and isIdleQueuedRecoverableSessionStall re-triggered recovery indefinitely. Reconcile the activity store from the authoritative idle declaration by clearing the session's embedded-run owners. The existing generation guard already excludes any newer run that re-armed activity, so a live requeued run is preserved. * fix(diagnostics): reconcile tool/model activity on authoritative idle cleanup clearDiagnosticEmbeddedRunActivityForSession (renamed from clearDiagnosticEmbeddedRunsForSession) now clears the aborted run's tool and model markers alongside the embedded-run owners, matching the default markDiagnosticEmbeddedRunEnded teardown. Clearing only the owner set left the lane as idle + orphaned tool/model activity, which isIdleQueuedRecoverableSessionStall still treats as recoverable while work is queued, so the liveness sweep kept re-triggering recovery instead of converging. Adds regression cases with stale tool and model markers plus queued work. * test(phone-control): align service mocks with keyed store API * fix(diagnostics): preserve rearmed recovery activity * fix(diagnostics): clear recovered owner markers * fix(diagnostics): clear recovered embedded work keys * fix(diagnostics): ignore stale same-key recovery owners * fix(diagnostics): preserve same-session recovery rearm * fix(diagnostics): ignore stale queued activity starts * fix(diagnostics): record recovery cutoffs for empty activity * fix(diagnostics): preserve fresh recovery markers * fix(diagnostics): prune stale activity before fresh recovery block --------- Co-authored-by: Peter Steinberger <[email protected]>
1 parent 785849d commit c0195f7

6 files changed

Lines changed: 949 additions & 18 deletions

File tree

extensions/phone-control/index.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import fs from "node:fs/promises";
22
import os from "node:os";
33
import path from "node:path";
4-
import type { OpenKeyedStoreOptions } from "openclaw/plugin-sdk/plugin-state-runtime";
5-
import type { PluginStateKeyedStore } from "openclaw/plugin-sdk/plugin-state-runtime";
4+
import type {
5+
OpenKeyedStoreOptions,
6+
PluginStateKeyedStore,
7+
} from "openclaw/plugin-sdk/plugin-state-runtime";
68
import {
79
createPluginStateKeyedStoreForTests,
810
resetPluginStateStoreForTests,

extensions/phone-control/index.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
21
import {
32
asDateTimestampMs,
43
resolveExpiresAtMsFromDurationMs,
@@ -166,7 +165,7 @@ async function disarmNow(params: {
166165
if (!state) {
167166
return { changed: false, restored: [], removed: [] };
168167
}
169-
const cfg = api.runtime.config.current() as OpenClawConfig;
168+
const cfg = api.runtime.config.current();
170169
const allow = new Set(normalizeAllowList(cfg));
171170
const deny = new Set(normalizeDenyList(cfg));
172171
const removed: string[] = [];
@@ -430,7 +429,7 @@ export default definePluginEntry({
430429
}
431430

432431
const commands = resolveCommandsForGroup(group);
433-
const cfg = api.runtime.config.current() as OpenClawConfig;
432+
const cfg = api.runtime.config.current();
434433
const allowSet = new Set(normalizeAllowList(cfg));
435434
const denySet = new Set(normalizeDenyList(cfg));
436435

src/infra/diagnostic-events.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,6 +1101,10 @@ export function emitInternalDiagnosticEvent(event: DiagnosticEventInput) {
11011101
emitDiagnosticEventWithTrust(event, false, { internal: true });
11021102
}
11031103

1104+
export function getInternalDiagnosticEventSequence(): number {
1105+
return getDiagnosticEventsState().seq;
1106+
}
1107+
11041108
export function emitTrustedDiagnosticEvent(event: DiagnosticEventInput) {
11051109
emitDiagnosticEventWithTrust(event, true);
11061110
}

0 commit comments

Comments
 (0)