fix(cron): classify recovered agentTurn as non-fatal when finalAssistantVisibleText exists#96266
fix(cron): classify recovered agentTurn as non-fatal when finalAssistantVisibleText exists#96266evan-YM wants to merge 1 commit into
Conversation
|
Codex review: found issues before merge. Reviewed July 1, 2026, 5:20 AM ET / 09:20 UTC. Summary PR surface: Source +13, Tests +67. Total +80 across 2 files. Reproducibility: yes. Current main and v2026.6.11 still have the recovered-error fatalization path, and the canonical issue has a reduced scheduled cron reproduction; I did not run a live cron/channel job in this read-only review. Review metrics: 1 noteworthy metric.
Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Mantis proof suggestion Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Land one canonical cron payload-outcome fix that ties final-answer recovery to proven non-terminal or tool-warning evidence while preserving genuine fatal error suppression. Do we have a high-confidence way to reproduce the issue? Yes. Current main and v2026.6.11 still have the recovered-error fatalization path, and the canonical issue has a reduced scheduled cron reproduction; I did not run a live cron/channel job in this read-only review. Is this the best way to solve the issue? No. The helper is the right layer, but this PR treats final assistant text as a universal recovery signal; the safer fix must narrow recovery to proven non-terminal/tool-warning evidence or get an explicit maintainer decision for broader semantics. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against f3ac874fd215. Label changesLabel justifications:
Evidence reviewedPR surface: Source +13, Tests +67. Total +80 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
…ssistantVisibleText exists When an isolated cron agentTurn hits a transient tool error mid-run and the agent recovers with a successful finalAssistantVisibleText, the run was misclassified as fatal because no existing recovery gate could fire. The exec error lacked the required metadata markers, text prefixes, or deliverable post-error payloads. Add hasRecoveredByFinalAnswer gate that treats a non-empty finalAssistantVisibleText as recovery proof when the session completed without a run-level error or fatal failure signal. Also couple the recovery gate with delivery-payload selection so the final report is dispatched on all channels — including Feishu/Slack where preferFinalAssistantVisibleText is false — rather than falling back to the recovered error text. Related to openclaw#96255 Co-Authored-By: Claude <[email protected]>
3f42f88 to
3de7817
Compare
|
maintainer closeout: this candidate is not safe to land.
The safe boundary is typed producer evidence that the failure was nonterminal, or a first-class degraded cron outcome. The canonical issue remains open for that work. |
Summary
Cron
agentTurnruns that encounter a transient tool error mid-run and recover with a successfulfinalAssistantVisibleTextare now classified asokinstead oferror, ensuring the success announce delivery is dispatched.resolveCronPayloadOutcomeclassified runs as fatal when no existing recovery gate could fire. The four gates all failed because the raw exec error payload lacked the required metadata markers (nonTerminalToolErrorWarning), text prefixes (⚠️ 🛠️), or deliverable post-error payloads (hasSuccessfulPayloadAfterLastError). The agent'sfinalAssistantVisibleText— which proved recovery — was never consulted.hasRecoveredByFinalAnswergate that treats a non-emptyfinalAssistantVisibleTextas recovery proof when the session completed without a run-level error or fatal failure signal.src/cron/isolated-agent/helpers.ts(+17/-2: newhasRecoveredByFinalAnswergate + delivery coupling for false-policy channels),src/cron/isolated-agent.helpers.test.ts(+83/-12: 2 updated tests + 4 new tests including Feishu/Slack channel regression)fatalForCronfailure signal precedence,dispatchCronDeliverycall site, channel output policy resolver, SDK surface, config, or migration paths.What Problem This Solves
Cron
agentTurnruns withdelivery.mode: "announce"were silently failing every night when the agent hit a transient tool error mid-run (e.g.execrejecting shell redirect syntax like>,2>&1), retried successfully, completed all remaining steps, and emitted a full final report. The cron runner misclassified the recovered run asstatus: "error"because no existing recovery gate consultedfinalAssistantVisibleText— the agent runtime's own signal of successful completion. The operator received a failure notification synthesized from the already-recovered tool error instead of the actual report.Change Type & Scope
Change Type
Scope
Linked Issue
Motivation
A cron
agentTurnwithdelivery.mode: "announce"was silently failing every night for 6 consecutive days. The agent hit a transientexectool error (shell redirect syntax rejected), retried successfully, completed 60+ further tool calls, and emitted a full final report — but the operator received no report at all. The cron run log showedstatus=errorwith a synthesized failure notification built from the already-recovered tool error.This affects any cron whose agent habitually probes with shell-isms the
exectool rejects (>,2>&1,;, quoted python one-liners) and then retries — a common recovery pattern across multiple model providers.Review Contract
Real Behavior Proof
Behavior addressed: Cron
agentTurnwith recovered tool error +finalAssistantVisibleText→ misclassified aserror, delivery skipped. After fix: classification corrected took, final report delivered on all channels including Feishu/Slack (wherepreferFinalAssistantVisibleTextis false).Real environment tested: Linux 4.19.112-2.el8.x86_64, Node 24.13.1, branch
fix/cron-recovered-final-answer-96255, built withpnpm build(883s, clean exit)Exact steps or command run after this patch:
Evidence after fix:
Recovery classification matrix (from the 5 real scenarios above):
Unit test results:
Observed result after fix:
hasFatalStructuredErrorPayloadis false whenfinalAssistantVisibleTextproves recovery (scenario 1)preferFinalAssistantVisibleText: false), the recovered final report is delivered instead of the error payload (scenario 2, ClawSweeper P1)runLevelErrorandfatalForCroncontinue to produce fatal classification (scenarios 3, 4)What was not tested:
run-executor.tsinterim retry path (analyzed in code: line 602isErrorhard gate prevents impact)验证环境
fix/cron-recovered-final-answer-96255Evidence
Terminal proof (5 real scenarios via
npx tsx)Unit tests (89 passed across 3 files)
Environment
fix/cron-recovered-final-answer-96255pnpm build(883s, clean exit)Risks and Mitigations
runLevelErrorbeing set, wherefinalAssistantVisibleTextcontains only a partial/placeholder message. Mitigation: the!runLevelErrorguard prevents this — provider errors, context overflows, and abort/timeout scenarios all setrunLevelError.errormay becomeok, but runs that wereokremainok. No config, migration, or SDK changes.Security Impact
Compatibility / Migration
Human Verification
AI Assistance 🤖
hasFatalStructuredErrorPayload→ designedhasRecoveredByFinalAnsweras the minimal additionRelated to #96255