From fd2fe46e9847aade18ab4bcf3132dcf5b47cce67 Mon Sep 17 00:00:00 2001 From: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 11:28:33 +0000 Subject: [PATCH] fix(clawsweeper): address review for automerge-openclaw-openclaw-82891 (1) --- ...mpt.spawn-workspace.context-engine.test.ts | 52 +++++++++++++++++++ src/agents/pi-embedded-runner/run/attempt.ts | 3 ++ 2 files changed, 55 insertions(+) diff --git a/src/agents/pi-embedded-runner/run/attempt.spawn-workspace.context-engine.test.ts b/src/agents/pi-embedded-runner/run/attempt.spawn-workspace.context-engine.test.ts index c3abd3dafd6..4be7f87ad77 100644 --- a/src/agents/pi-embedded-runner/run/attempt.spawn-workspace.context-engine.test.ts +++ b/src/agents/pi-embedded-runner/run/attempt.spawn-workspace.context-engine.test.ts @@ -96,6 +96,26 @@ function expectFields(actual: Record, expected: Record { + const lockId = hoisted.acquireSessionWriteLockMock.mock.calls.length; + events.push(`acquire-${lockId}`); + return { + release: async () => { + events.push(`release-${lockId}`); + }, + }; + }); + return events; +} + +function expectInitialLockReleasedBeforePostTurnWrite(events: string[]) { + expect(events.indexOf("release-1")).toBeGreaterThan(events.indexOf("acquire-1")); + expect(events.indexOf("acquire-2")).toBeGreaterThan(events.indexOf("release-1")); + expect(events.indexOf("release-2")).toBeGreaterThan(events.indexOf("acquire-2")); +} + function createTestContextEngine(params: Partial): AttemptContextEngine { return { info: { @@ -773,6 +793,7 @@ describe("runEmbeddedAttempt context engine sessionKey forwarding", () => { }); it("skips blank visible prompts with replay history before provider submission", async () => { + const lockEvents = trackSessionWriteLocks(); const sessionPrompt = vi.fn(async () => { throw new Error("blank prompt should not be submitted"); }); @@ -809,6 +830,35 @@ describe("runEmbeddedAttempt context engine sessionKey forwarding", () => { "prompt skipped event", ); expect(requireRecord(skipped.data, "prompt skipped data").reason).toBe("blank_user_prompt"); + expectInitialLockReleasedBeforePostTurnWrite(lockEvents); + }); + + it("releases the initial session lock before before_agent_run block finalizers", async () => { + const lockEvents = trackSessionWriteLocks(); + const sessionPrompt = vi.fn(async () => { + throw new Error("blocked prompt should not be submitted"); + }); + const runBeforeAgentRun = vi.fn(async () => ({ + pluginId: "test-policy", + decision: { outcome: "block", reason: "Blocked by test policy." }, + })); + hoisted.getGlobalHookRunnerMock.mockReturnValue({ + hasHooks: vi.fn((name: string) => name === "before_agent_run"), + runBeforeAgentRun, + }); + + const result = await createContextEngineAttemptRunner({ + contextEngine: createContextEngineBootstrapAndAssemble(), + sessionKey, + tempPaths, + sessionPrompt, + }); + + expect(runBeforeAgentRun).toHaveBeenCalledTimes(1); + expect(sessionPrompt).not.toHaveBeenCalled(); + expect(result.finalPromptText).toBeUndefined(); + expect(result.promptErrorSource).toBe("hook:before_agent_run"); + expectInitialLockReleasedBeforePostTurnWrite(lockEvents); }); it("uses assembled context as the default precheck authority", async () => { @@ -846,6 +896,7 @@ describe("runEmbeddedAttempt context engine sessionKey forwarding", () => { }); it("honors context engines that opt into preassembly overflow authority", async () => { + const lockEvents = trackSessionWriteLocks(); let sawPrompt = false; const hugeHistory = "large raw history ".repeat(2_000); @@ -878,6 +929,7 @@ describe("runEmbeddedAttempt context engine sessionKey forwarding", () => { expect(result.promptErrorSource).toBe("precheck"); expect(result.preflightRecovery?.route).toBe("compact_only"); expect(hoisted.preemptiveCompactionCalls.at(-1)).toHaveProperty("unwindowedMessages"); + expectInitialLockReleasedBeforePostTurnWrite(lockEvents); }); it("snapshots pre-assembly messages before assemble even when the engine windows in place", async () => { diff --git a/src/agents/pi-embedded-runner/run/attempt.ts b/src/agents/pi-embedded-runner/run/attempt.ts index e5e9f576795..9e932132021 100644 --- a/src/agents/pi-embedded-runner/run/attempt.ts +++ b/src/agents/pi-embedded-runner/run/attempt.ts @@ -4099,6 +4099,9 @@ export async function runEmbeddedAttempt( }); } + await sessionLockController.waitForSessionEvents(activeSession); + await sessionLockController.releaseForPrompt(); + // Capture snapshot before compaction wait so we have complete messages if timeout occurs // Check compaction state before and after to avoid race condition where compaction starts during capture // Use session state (not subscription) for snapshot decisions - need instantaneous compaction status