Files
openclaw/src/auto-reply
Jerry-Xin 6f90ee4cb8 fix: recover terminal session status on visible inbound turns (#89045)
* fix: recover terminal session status on visible inbound turns (#86827)

When a group chat session enters a terminal status (failed/timeout/killed),
subsequent visible inbound messages now automatically recover the session by
clearing stale lifecycle fields while preserving the session ID and transcript
continuity.

Changes:
- session.ts: detect terminal status on visible turns and clear status/
  startedAt/endedAt/runtimeMs/abortedLastRun without rotating sessionId
- dispatch-from-config.ts: force-clear stale active reply operations for
  terminal sessions and retry admission once
- agent.ts: mirror terminal recovery in the agent API dispatch path
- kernel.ts: add zero-count visible dispatch warning diagnostic
- types.ts: add 'warning' to ChannelTurnLogEvent event union

* fix: guard terminal recovery from concurrent force-clear race

When two visible messages arrive against the same terminal session
snapshot, the second turn could force-fail the first turn's freshly
admitted recovery operation, dropping the very message the recovery
path exists to save.

Add a terminalRecovery flag on ReplyOperation that is set after a
recovery turn clears the proven stale leftover and admits its own
operation. The force-clear branch now skips operations marked as
in-flight terminal recoveries, letting concurrent turns fall through
to normal busy/wait handling instead.

Add a two-turn regression test that gates the first recovery turn
open, races a second visible turn against the same terminal snapshot,
and asserts neither turn's operation is incorrectly killed.

Also fix missing FinalizedMsgContext import in kernel.ts.

* fix: avoid return value in Promise executor to satisfy lint

* fix: gate terminal force-clear to visible reply turns

A heartbeat/control turn can pass the early active-run short-circuit, reach
the terminal force-clear branch, and abort an in-flight visible recovery
operation that a concurrent visible turn just admitted (before that op is
marked terminalRecovery). Gate the force-clear to visible reply turns so
non-visible turns fall through to normal busy/skip handling instead of
killing the recovery they are meant to protect.

Adds a focused regression test exercising a heartbeat turn that reaches the
force-clear branch against a terminal session snapshot with an active
recovery operation present; it must leave that operation intact and skip.

* fix: verify session identity before terminal force-clear

* fix: mark clean no-stale terminal recovery to survive concurrent visible turn

The same-session terminal-recovery race could still drop a reply when two
visible turns raced the same failed snapshot. The terminalRecovery marker was
set only on the post-force-clear re-admission path, never on the clean no-stale
admission path. So when the first turn admitted cleanly (no stale op to clear),
its recovery op stayed terminalRecovery=false and a second concurrent visible
turn force-cleared it, dropping the first reply (#86827).

Consolidate marking to the single owned-admission choke point that both the
clean no-stale admission and the re-admission-after-force-clear flow through.
Genuine stale leftovers from the original failed run never pass through this
admission, so they stay unmarked and remain force-clearable.

Add a no-stale regression twin to the existing stale-race test.

* fix: suppress zero-count visible-dispatch warning for observed-delivery turns

maybeWarnZeroCountVisibleDispatch re-implemented a partial visibility
check that omitted observedReplyDelivery, so visible turns delivered via
the observed-delivery path (queuedFinal=false, zero counts,
observedReplyDelivery=true) falsely tripped the silent-drop sentinel and
emitted a bogus zero-count-visible-dispatch warning/event.

Use the canonical hasVisibleChannelTurnDispatch helper for the warning
suppression so all non-count delivery paths (observedReplyDelivery,
fallback, summary, queuedFinal) are honored. Add regression tests
covering the observed-delivery case (no warning) and a genuinely empty
visible dispatch (still warns).

* test: read persisted session store in failed-group recovery test

---------

Co-authored-by: 忻役 <xinyi@mininglamp.com>
2026-06-28 15:45:37 -07:00
..