diff --git a/src/hooks/ralph-loop/completion-promise-detector.test.ts b/src/hooks/ralph-loop/completion-promise-detector.test.ts
index 704517732..bbb2206fb 100644
--- a/src/hooks/ralph-loop/completion-promise-detector.test.ts
+++ b/src/hooks/ralph-loop/completion-promise-detector.test.ts
@@ -273,6 +273,28 @@ describe("detectCompletionInSessionMessages", () => {
// #then
expect(detected).toBe(true)
})
+
+ test("#when promise is VERIFIED #then semantic completion should NOT trigger", async () => {
+ // #given
+ const messages: SessionMessage[] = [
+ {
+ info: { role: "assistant" },
+ parts: [{ type: "text", text: "The task is complete. All work has been finished." }],
+ },
+ ]
+ const ctx = createPluginInput(messages)
+
+ // #when
+ const detected = await detectCompletionInSessionMessages(ctx, {
+ sessionID: "session-123",
+ promise: "VERIFIED",
+ apiTimeoutMs: 1000,
+ directory: "/tmp",
+ })
+
+ // #then
+ expect(detected).toBe(false)
+ })
})
})
diff --git a/src/hooks/ralph-loop/completion-promise-detector.ts b/src/hooks/ralph-loop/completion-promise-detector.ts
index 39322e536..cd02ce7f7 100644
--- a/src/hooks/ralph-loop/completion-promise-detector.ts
+++ b/src/hooks/ralph-loop/completion-promise-detector.ts
@@ -49,8 +49,9 @@ export function detectCompletionInTranscript(
if (entry.type === "user") continue
if (startedAt && entry.timestamp && entry.timestamp < startedAt) continue
if (pattern.test(line)) return true
- // Fallback: check for semantic completion
- if (detectSemanticCompletion(line)) {
+ // Fallback: semantic completion only for DONE promise and assistant entries
+ const isAssistantEntry = entry.type === "assistant" || entry.type === "text"
+ if (promise === "DONE" && isAssistantEntry && detectSemanticCompletion(line)) {
log("[ralph-loop] WARNING: Semantic completion detected in transcript (agent used natural language instead of DONE)")
return true
}
@@ -118,8 +119,8 @@ export async function detectCompletionInSessionMessages(
return true
}
- // Fallback: check for semantic completion
- if (detectSemanticCompletion(responseText)) {
+ // Fallback: semantic completion only for DONE promise
+ if (options.promise === "DONE" && detectSemanticCompletion(responseText)) {
log("[ralph-loop] WARNING: Semantic completion detected (agent used natural language instead of DONE)", {
sessionID: options.sessionID,
})