Bug type: Behavior bug (incorrect output/state without crash)
Beta release blocker: No
Summary
resolveCronChannelOutputPolicy at dist/run-session-state-*.js:17-22 returns { preferFinalAssistantVisibleText: false } whenever no channel ID is resolved — which is the case for every --no-deliver cron — and this disables the hasRecoveredToolWarning rescue at helpers-DIfpiLk_.js:142, causing claude-cascade-style isolated dispatches to record status: error whenever their final tool call produces a ⚠️🛠️ payload, even though the agent's work succeeded and finalAssistantVisibleText is populated.
Steps to reproduce
- On v2026.5.28, dispatch an isolated cron with
--no-deliver --expect-final --session isolated, agent prompt ending with a tool call (e.g. ~/bin/imsg send ...).
- Let it run to completion. Confirm via the codex rollout JSONL that the agent emitted a
task_complete event and a clean agent_message final summary.
- Inspect
openclaw cron runs --id <jobId>.
Verification dispatches in our environment (same shape, different patch states):
3416705b-c0e0-48ce-9a85-5ed2f02ed576 (pre-patch): status: error, error: "⚠️ 🛠️ \show > (agent)` failed", duration 322s. task_complete` fired and two real git commits shipped (verified independently).
e092ae7c-553b-41d2-a094-75cafe641ae9 (post-patch, single-line dist flip described below): status: ok, no error, duration 33s, same ⚠️🛠️ payload preserved as warn severity diagnostic, summary carries agent's final text.
Expected behavior
When --no-deliver is set (deliveryPlan.mode === "none"), the agent's finalAssistantVisibleText IS the authoritative outcome (no external delivery to worry about). The hasRecoveredToolWarning rescue should fire if the only error payloads are tool warnings (text starts with ⚠️ 🛠️ ) AND a finalAssistantVisibleText is present — exactly the case present in every observed instance — yielding status: ok with the tool warning preserved as a warn-severity diagnostic.
Actual behavior
preferFinalAssistantVisibleText is false (no-channel default) → hasRecoveredToolWarning hard-gates to false → hasFatalStructuredErrorPayload is true → outcome: error. The agent's actual final text is overwritten in the cron summary by the tool-warning text. Observed across 5+ claude-cascade-* dispatches over the past week, 3 of which were independently verified to have shipped their underlying work correctly.
OpenClaw version
2026.5.28 (e932160)
OS
macOS 26.4.1 arm64 (Darwin 25.4.0)
Install method
npm install -g openclaw under LaunchAgent (ai.openclaw.gateway, port 18789)
Model
openai-codex/gpt-5.5
Provider / routing chain
openclaw → openai-codex (OAuth) → gpt-5.5
Additional provider/model setup details
NOT_ENOUGH_INFO — bug is in cron-outcome classification, not provider chain.
Logs, screenshots, and evidence
# Pre-patch diagnostic (cron 3416705b, 2026-06-05 11:52:14Z):
status: error
error: ⚠️ 🛠️ `show > (agent)` failed
duration: 322457ms
diagnostics:
[tool/error] ⚠️ 🛠️ `show > (agent)` failed
[agent-run/error] ⚠️ 🛠️ `show > (agent)` failed
# Codex rollout for same cron showed (last events before turn closed):
... task_complete event fired
... agent_message: "Shipped, Bobble. Files touched: [...] Commits: 5360ee3 in ~/.openclaw, 444c27e4 in /Users/Badman/Claude..."
# Post-patch diagnostic (cron e092ae7c, 2026-06-05 12:23Z, same dispatch shape):
status: ok
error: (none)
duration: 33012ms
summary: "Line count: \`632\`. iMessage send result: \`{\"status\":\"sent\"}\`."
diagnostics:
[tool/warn] ⚠️ 🛠️ \`~/.openclaw/scripts/imsg-angie send +17036759608 ... (agent)\` failed
Root cause (located via dist source read):
dist/run-session-state-*.js (v5.28 file is run-session-state-D6S4JhOH.js), function resolveCronChannelOutputPolicy:
async function resolveCronChannelOutputPolicy(channel) {
const channelId = normalizeOptionalLowercaseString(channel);
if (!channelId) return { preferFinalAssistantVisibleText: false }; // ← BUG: too-pessimistic default
const { getChannelPlugin } = await loadChannelPluginRuntime();
return { preferFinalAssistantVisibleText: getChannelPlugin(channelId)?.outbound?.preferFinalAssistantVisibleText === true };
}
The early-return defaults to false, but the only situations where this branch fires are (a) --no-deliver cron (explicit, user-stated that agent owns the final outcome), or (b) misconfigured cron with broken channel resolution (in which case agent text is still the only authoritative outcome). In both cases, true is the correct default — the rescue path at helpers-DIfpiLk_.js:142 was designed precisely for this scenario.
Both call sites inherit the bug:
dist/isolated-agent-*.js:948 (isolated-agent-6jikzXvw.js on v5.28)
dist/run-executor.runtime-*.js:294 (run-executor.runtime-C3DKNYjg.js on v5.28)
Proposed fix
One-line change at dist/run-session-state-*.js:19:
- if (!channelId) return { preferFinalAssistantVisibleText: false };
+ if (!channelId) return { preferFinalAssistantVisibleText: true };
A more conservative variant plumbs deliveryPlan.mode === "none" to the call site and forces true only for explicit --no-deliver, but I cannot construct a case where false is correct when there is no channel resolved — if there is no channel, the cron cannot deliver anything, so whether tool warnings are recoverable should depend on the agent's final text (the rescue's design intent), not on a channel policy that does not exist.
Local mitigation deployed and verified in our environment as described above. Happy to open a PR if useful.
Impact and severity
- Affected: Anyone running isolated cron jobs with
delivery.mode: "none" (--no-deliver) where the agent's final step is a tool call. Includes managed Memory Dreaming Promotion (uses delivery: { mode: "none" }), any claude-cascade-*-style ad-hoc dispatches, and any pattern where an agent owns its own delivery in-loop.
- Severity: Medium. No data loss; agent work actually succeeds. But cron
status: error becomes unreliable as a monitoring signal — every successful cascade dispatch trips downstream cron_failures HIGH alerts after 3 consecutive misclassifications, and "did the cron actually work?" requires rollout-file forensics every time instead of trusting the status field.
- Frequency: Always — 5/5 observed
claude-cascade-* dispatches over the past week.
- Consequence: False-positive monitoring alerts; operator time spent verifying success that should be trusted from the status field; loss of the cron status field's signal value.
Additional information
Related but distinct branches of the same function:
Both threads cover different branches; this report covers the no-channel default specifically.
Bug type: Behavior bug (incorrect output/state without crash)
Beta release blocker: No
Summary
resolveCronChannelOutputPolicyatdist/run-session-state-*.js:17-22returns{ preferFinalAssistantVisibleText: false }whenever no channel ID is resolved — which is the case for every--no-delivercron — and this disables thehasRecoveredToolWarningrescue athelpers-DIfpiLk_.js:142, causingclaude-cascade-style isolated dispatches to recordstatus: errorwhenever their final tool call produces a⚠️🛠️payload, even though the agent's work succeeded andfinalAssistantVisibleTextis populated.Steps to reproduce
--no-deliver --expect-final --session isolated, agent prompt ending with a tool call (e.g.~/bin/imsg send ...).task_completeevent and a cleanagent_messagefinal summary.openclaw cron runs --id <jobId>.Verification dispatches in our environment (same shape, different patch states):
3416705b-c0e0-48ce-9a85-5ed2f02ed576(pre-patch):status: error,error: "⚠️ 🛠️ \show > (agent)` failed", duration 322s.task_complete` fired and two real git commits shipped (verified independently).e092ae7c-553b-41d2-a094-75cafe641ae9(post-patch, single-line dist flip described below):status: ok, no error, duration 33s, same⚠️🛠️payload preserved aswarnseverity diagnostic,summarycarries agent's final text.Expected behavior
When
--no-deliveris set (deliveryPlan.mode === "none"), the agent'sfinalAssistantVisibleTextIS the authoritative outcome (no external delivery to worry about). ThehasRecoveredToolWarningrescue should fire if the only error payloads are tool warnings (textstarts with⚠️ 🛠️) AND afinalAssistantVisibleTextis present — exactly the case present in every observed instance — yieldingstatus: okwith the tool warning preserved as awarn-severity diagnostic.Actual behavior
preferFinalAssistantVisibleTextisfalse(no-channel default) →hasRecoveredToolWarninghard-gates to false →hasFatalStructuredErrorPayloadistrue→outcome: error. The agent's actual final text is overwritten in the cron summary by the tool-warning text. Observed across 5+claude-cascade-*dispatches over the past week, 3 of which were independently verified to have shipped their underlying work correctly.OpenClaw version
2026.5.28 (e932160)OS
macOS 26.4.1 arm64 (Darwin 25.4.0)
Install method
npm install -g openclawunder LaunchAgent (ai.openclaw.gateway, port 18789)Model
openai-codex/gpt-5.5Provider / routing chain
openclaw → openai-codex (OAuth) → gpt-5.5Additional provider/model setup details
NOT_ENOUGH_INFO — bug is in cron-outcome classification, not provider chain.
Logs, screenshots, and evidence
Root cause (located via dist source read):
dist/run-session-state-*.js(v5.28 file isrun-session-state-D6S4JhOH.js), functionresolveCronChannelOutputPolicy:The early-return defaults to
false, but the only situations where this branch fires are (a)--no-delivercron (explicit, user-stated that agent owns the final outcome), or (b) misconfigured cron with broken channel resolution (in which case agent text is still the only authoritative outcome). In both cases,trueis the correct default — the rescue path athelpers-DIfpiLk_.js:142was designed precisely for this scenario.Both call sites inherit the bug:
dist/isolated-agent-*.js:948(isolated-agent-6jikzXvw.json v5.28)dist/run-executor.runtime-*.js:294(run-executor.runtime-C3DKNYjg.json v5.28)Proposed fix
One-line change at
dist/run-session-state-*.js:19:A more conservative variant plumbs
deliveryPlan.mode === "none"to the call site and forcestrueonly for explicit--no-deliver, but I cannot construct a case wherefalseis correct when there is no channel resolved — if there is no channel, the cron cannot deliver anything, so whether tool warnings are recoverable should depend on the agent's final text (the rescue's design intent), not on a channel policy that does not exist.Local mitigation deployed and verified in our environment as described above. Happy to open a PR if useful.
Impact and severity
delivery.mode: "none"(--no-deliver) where the agent's final step is a tool call. Includes managed Memory Dreaming Promotion (usesdelivery: { mode: "none" }), anyclaude-cascade-*-style ad-hoc dispatches, and any pattern where an agent owns its own delivery in-loop.status: errorbecomes unreliable as a monitoring signal — every successful cascade dispatch trips downstreamcron_failuresHIGH alerts after 3 consecutive misclassifications, and "did the cron actually work?" requires rollout-file forensics every time instead of trusting the status field.claude-cascade-*dispatches over the past week.Additional information
Related but distinct branches of the same function:
getChannelPlugin(channelId)?.outbound?.preferFinalAssistantVisibleTextreturns false; affected reporter was on Discord channel). Different mechanism — this report's patch does not fix that case.clawsweeper:linked-pr-openbut PR did not land; currently stale-bot-warned. This report's patch fixes the--no-deliversubcase of that bug class.Both threads cover different branches; this report covers the no-channel default specifically.