Summary
Paseo 0.3.1 can complete an OMP turn before its user prompt is associated with that turn. If OMP emits message_end(role=custom) after turn_start but before the prompt's user message_end, Paseo emits turn_completed; lifecycle becomes idle and a parent can receive finished even though OMP continues working.
Current environment: Paseo 0.3.1, OMP 17.2.12. A matching incident trace showed running at 01:55:35.394, finished at 01:55:35.440, first tool at 01:55:42.797, and actual turn end at 02:04:20.877.
Minimal deterministic reproducer
Start session.run("do work") with the existing fake OMP runtime, then deliver exactly:
turn_start
message_end { message: { role: "custom", content: "startup notice" } }
# expect zero turn_completed; current handler calls completeTurn here
message_end { message: { role: "user", content: "do work" } }
tool_execution_start ...
agent_end ...
The fake already provides beginTurn(), acceptCustomMessage(), and acceptPrompt(). Put acceptCustomMessage() before acceptPrompt(); completion should occur only after terminal agent_end.
Root cause
The dispatcher sets activeTurnHasUserMessage only on user message_end. The custom branch calls completeTurn(turnId, []) while it is false, and completeTurn emits turn_completed. Running→idle then drives notifySafely("finished").
Current main d012b6f:
#2232 is parent idle after terminal agent_end while OMP-internal task children remain active. #2245 only gates completeTurnAfterProviderIdle on those children. This repro has no subagent and no agent_end before false completion; it calls completeTurn directly from handleMessageEnd, so #2245 cannot cover it.
Expected
A custom message must not complete an active prompt merely because its user message_end has not arrived. Emit one completion only after the real terminal signal.
Summary
Paseo 0.3.1 can complete an OMP turn before its user prompt is associated with that turn. If OMP emits
message_end(role=custom)afterturn_startbut before the prompt's usermessage_end, Paseo emitsturn_completed; lifecycle becomes idle and a parent can receivefinishedeven though OMP continues working.Current environment: Paseo 0.3.1, OMP 17.2.12. A matching incident trace showed running at 01:55:35.394,
finishedat 01:55:35.440, first tool at 01:55:42.797, and actual turn end at 02:04:20.877.Minimal deterministic reproducer
Start
session.run("do work")with the existing fake OMP runtime, then deliver exactly:The fake already provides
beginTurn(),acceptCustomMessage(), andacceptPrompt(). PutacceptCustomMessage()beforeacceptPrompt(); completion should occur only after terminalagent_end.Root cause
The dispatcher sets
activeTurnHasUserMessageonly on usermessage_end. The custom branch callscompleteTurn(turnId, [])while it is false, andcompleteTurnemitsturn_completed. Running→idle then drivesnotifySafely("finished").Current main
d012b6f:Not #2232 / #2245
#2232 is parent idle after terminal
agent_endwhile OMP-internal task children remain active. #2245 only gatescompleteTurnAfterProviderIdleon those children. This repro has no subagent and noagent_endbefore false completion; it callscompleteTurndirectly fromhandleMessageEnd, so #2245 cannot cover it.Expected
A custom message must not complete an active prompt merely because its user
message_endhas not arrived. Emit one completion only after the real terminal signal.