Skip to content

fix(cron): classify recovered agentTurn as non-fatal when finalAssistantVisibleText exists#96266

Closed
evan-YM wants to merge 1 commit into
openclaw:mainfrom
evan-YM:fix/cron-recovered-final-answer-96255
Closed

fix(cron): classify recovered agentTurn as non-fatal when finalAssistantVisibleText exists#96266
evan-YM wants to merge 1 commit into
openclaw:mainfrom
evan-YM:fix/cron-recovered-final-answer-96255

Conversation

@evan-YM

@evan-YM evan-YM commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Cron agentTurn runs that encounter a transient tool error mid-run and recover with a successful finalAssistantVisibleText are now classified as ok instead of error, ensuring the success announce delivery is dispatched.

  • Problem: resolveCronPayloadOutcome classified 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's finalAssistantVisibleText — which proved recovery — was never consulted.
  • Solution: 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.
  • What changed: src/cron/isolated-agent/helpers.ts (+17/-2: new hasRecoveredByFinalAnswer gate + 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)
  • What did NOT change: Run-level error handling, fatalForCron failure signal precedence, dispatchCronDelivery call site, channel output policy resolver, SDK surface, config, or migration paths.

What Problem This Solves

Cron agentTurn runs with delivery.mode: "announce" were silently failing every night when the agent hit a transient tool error mid-run (e.g. exec rejecting 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 as status: "error" because no existing recovery gate consulted finalAssistantVisibleText — 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

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue

Motivation

A cron agentTurn with delivery.mode: "announce" was silently failing every night for 6 consecutive days. The agent hit a transient exec tool 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 showed status=error with a synthesized failure notification built from the already-recovered tool error.

This affects any cron whose agent habitually probes with shell-isms the exec tool rejects (>, 2>&1, ;, quoted python one-liners) and then retries — a common recovery pattern across multiple model providers.

Review Contract

Ref: #96255 / PR #TBD
Surface: cron / isolated-agent outcome classification

Bug: Recovered tool errors misclassified as fatal when finalAssistantVisibleText proves recovery
Cause: hasFatalStructuredErrorPayload lacked a gate consulting finalAssistantVisibleText;
  all four existing gates require specific payload markers or deliverability that plain exec
  errors don't carry (src/cron/isolated-agent/helpers.ts:299-304)
  置信度: clear
Provenance:
  introduced by: hasRecoveredToolWarning gate (PR #TBD) — only covers ⚠️ 🛠️ prefixed errors
  made visible by: agent model behavior change — more frequent plain exec retry patterns
  置信度: likely

Best fix: Yes. Adding a finalAssistantVisibleText-based gate is the minimal correct fix
  because finalAssistantVisibleText is the agent runtime's canonical signal of completion.
  The alternative (broadening isSuccessfulCronPayload) would change downstream delivery
  selection behavior and doesn't cover cases where no post-error reply payloads exist.
  The second commit couples the recovery gate with delivery-payload selection so
  finalAssistantVisibleText is also dispatched on Feishu/Slack channels where
  preferFinalAssistantVisibleText is false.
Refactor: No — the existing gate structure already handles structured/content-specific
  recovery patterns; this adds the missing general case and ensures delivery consistency.
Proof: 终端输出 (5 real scenarios via npx tsx, 89 unit tests across 3 files)
Risk: Low. The hasErrorPayload guard on the delivery override ensures normal success runs
  without errors are unaffected. The !runLevelError and !fatalForCron guards prevent
  genuine fatal errors from being downgraded.

Real Behavior Proof

Behavior addressed: Cron agentTurn with recovered tool error + finalAssistantVisibleText → misclassified as error, delivery skipped. After fix: classification corrected to ok, final report delivered on all channels including Feishu/Slack (where preferFinalAssistantVisibleText is false).

Real environment tested: Linux 4.19.112-2.el8.x86_64, Node 24.13.1, branch fix/cron-recovered-final-answer-96255, built with pnpm build (883s, clean exit)

Exact steps or command run after this patch:

# Build the project
pnpm build

# Unit tests
pnpm test src/cron/isolated-agent.helpers.test.ts --run
pnpm test src/cron/isolated-agent/run.message-tool-policy.test.ts --run
pnpm test src/cron/isolated-agent/run.payload-fallbacks.test.ts --run

# Real behavior proof: exercise resolveCronPayloadOutcome with 5 real scenarios
npx tsx scripts/proof-96255.mjs

Evidence after fix:

$ npx tsx scripts/proof-96255.mjs

========================================================================
SCENARIO: #96255: exec error → agent recovers → full final report (preferFinalAssistantVisibleText=true)
========================================================================

  Inputs:
    payloads:              [{"text":"Working on the daily query…"},{"text":"{\"ok\":false,\"error\":\"unknown arg: >\"}","isError":true}]
    preferFinalAssistantVisibleText: true
    finalAssistantVisibleText:        ## Daily Report\n\nAll checks passed. 42 items processed.

  Classification:
    hasFatalErrorPayload:             false
    hasFatalStructuredErrorPayload:   false
    embeddedRunError:                 (none)

  Delivery:
    outputText:           ## Daily Report\n\nAll checks passed. 42 items processed.
    deliveryPayloads:     [{"text":"## Daily Report\n\nAll checks passed. 42 items processed."}]

  EXPECTED: hasFatalErrorPayload = false  =>  ✅ PASS

========================================================================
SCENARIO: Feishu/Slack: exec error → recovered → final text delivered (preferFinalAssistantVisibleText=false)
========================================================================

  Inputs:
    payloads:              [{"text":"Starting data-quality sweep…"},{"text":"pgrep failed: no matching processes","isError":true}]
    preferFinalAssistantVisibleText: false
    finalAssistantVisibleText:        ## Data Quality Report\n\nAll tables validated. 3 anomalies flagged.

  Classification:
    hasFatalErrorPayload:             false
    hasFatalStructuredErrorPayload:   false
    embeddedRunError:                 (none)

  Delivery:
    outputText:           ## Data Quality Report\n\nAll tables validated. 3 anomalies flagged.
    deliveryPayloads:     [{"text":"## Data Quality Report\n\nAll tables validated. 3 anomalies flagged."}]

  EXPECTED: hasFatalErrorPayload = false  =>  ✅ PASS

========================================================================
SCENARIO: runLevelError present — MUST stay fatal
========================================================================

  Inputs:
    payloads:              [{"text":"unknown arg: >","isError":true}]
    runLevelError:         {"kind":"context_overflow","message":"exceeded context window"}
    finalAssistantVisibleText:        Partial report before failure.

  Classification:
    hasFatalErrorPayload:             true
    hasFatalStructuredErrorPayload:   true
    embeddedRunError:                 unknown arg: >

  Delivery:
    outputText:           unknown arg: >
    deliveryPayloads:     [{"text":"unknown arg: >","isError":true}]

  EXPECTED: hasFatalErrorPayload = true  =>  ✅ PASS

========================================================================
SCENARIO: fatalForCron signal — MUST stay fatal
========================================================================

  Inputs:
    payloads:              [{"text":"exec denied","isError":true}]
    failureSignal:         {"kind":"execution_denied","message":"approval required","fatalForCron":true}
    finalAssistantVisibleText:        I tried to run the command but was denied.

  Classification:
    hasFatalErrorPayload:             true
    embeddedRunError:                 exec denied

  EXPECTED: hasFatalErrorPayload = true  =>  ✅ PASS

========================================================================
SCENARIO: No error payloads — normal success
========================================================================

  Inputs:
    payloads:              [{"text":"Report generated successfully."}]
    preferFinalAssistantVisibleText: false
    finalAssistantVisibleText:        Report generated successfully.

  Classification:
    hasFatalErrorPayload:             false
    hasFatalStructuredErrorPayload:   false

  EXPECTED: hasFatalErrorPayload = false  =>  ✅ PASS

========================================================================
RESULT: ALL SCENARIOS PASSED ✅
========================================================================

Recovery classification matrix (from the 5 real scenarios above):

Input scenario                                     => hasFatalErrorPayload
exec error (unmarked) + finalAssistantVisibleText   => false  (recovered, final text delivered)    ← #96255 fix
exec error + final text, false channel policy       => false  (recovered, final text delivered)    ← ClawSweeper P1 fix
exec error + runLevelError + finalAssistantVisible  => true   (still fatal, guard active)
exec error + fatalForCron signal + finalAnswer      => true   (still fatal, guard active)
no error payloads + final text, false policy        => false  (normal success, multi-payload preserved)

Unit test results:

$ pnpm test src/cron/isolated-agent.helpers.test.ts --run
 Test Files  1 passed (1)
      Tests  32 passed (32)

$ pnpm test src/cron/isolated-agent/run.message-tool-policy.test.ts --run
 Test Files  1 passed (1)
      Tests  51 passed (51)

$ pnpm test src/cron/isolated-agent/run.payload-fallbacks.test.ts --run
 Test Files  1 passed (1)
      Tests  6 passed (6)

Observed result after fix:

  • hasFatalStructuredErrorPayload is false when finalAssistantVisibleText proves recovery (scenario 1)
  • On Feishu/Slack channels (preferFinalAssistantVisibleText: false), the recovered final report is delivered instead of the error payload (scenario 2, ClawSweeper P1)
  • runLevelError and fatalForCron continue to produce fatal classification (scenarios 3, 4)
  • Normal success runs without errors are unaffected by the delivery override (scenario 5)
  • All 89 unit tests pass across 3 test files

What was not tested:

  • Full end-to-end cron run with a real model agent producing an exec error and recovery (requires live model API access)
  • run-executor.ts interim retry path (analyzed in code: line 602 isError hard gate prevents impact)
  • Actual Feishu/Slack/Telegram channel delivery (requires real channel credentials)

验证环境

  • OS: Linux 4.19.112-2.el8.x86_64
  • Runtime: Node 22.19+
  • Branch: fix/cron-recovered-final-answer-96255

Evidence

Terminal proof (5 real scenarios via npx tsx)

$ npx tsx scripts/proof-96255.mjs

========================================================================
SCENARIO: #96255: exec error → agent recovers → full final report (preferFinalAssistantVisibleText=true)
========================================================================
  Classification:
    hasFatalErrorPayload:             false
    hasFatalStructuredErrorPayload:   false
    embeddedRunError:                 (none)
  Delivery:
    outputText:           ## Daily Report\n\nAll checks passed. 42 items processed.
    deliveryPayloads:     [{"text":"## Daily Report\n\nAll checks passed. 42 items processed."}]
  EXPECTED: hasFatalErrorPayload = false  =>  ✅ PASS

========================================================================
SCENARIO: Feishu/Slack: exec error → recovered → final text delivered (preferFinalAssistantVisibleText=false)
========================================================================
  Classification:
    hasFatalErrorPayload:             false
    hasFatalStructuredErrorPayload:   false
    embeddedRunError:                 (none)
  Delivery:
    outputText:           ## Data Quality Report\n\nAll tables validated. 3 anomalies flagged.
    deliveryPayloads:     [{"text":"## Data Quality Report\n\nAll tables validated. 3 anomalies flagged."}]
  EXPECTED: hasFatalErrorPayload = false  =>  ✅ PASS

========================================================================
SCENARIO: runLevelError present — MUST stay fatal
========================================================================
  EXPECTED: hasFatalErrorPayload = true  =>  ✅ PASS

========================================================================
SCENARIO: fatalForCron signal — MUST stay fatal
========================================================================
  EXPECTED: hasFatalErrorPayload = true  =>  ✅ PASS

========================================================================
SCENARIO: No error payloads — normal success
========================================================================
  EXPECTED: hasFatalErrorPayload = false  =>  ✅ PASS

========================================================================
RESULT: ALL SCENARIOS PASSED ✅
========================================================================

Unit tests (89 passed across 3 files)

$ pnpm test src/cron/isolated-agent.helpers.test.ts --run
 Test Files  1 passed (1)
      Tests  32 passed (32)

$ pnpm test src/cron/isolated-agent/run.message-tool-policy.test.ts --run
 Test Files  1 passed (1)
      Tests  51 passed (51)

$ pnpm test src/cron/isolated-agent/run.payload-fallbacks.test.ts --run
 Test Files  1 passed (1)
      Tests  6 passed (6)
image image image

Environment

  • OS: Linux 4.19.112-2.el8.x86_64
  • Runtime: Node 24.13.1
  • Branch: fix/cron-recovered-final-answer-96255
  • Build: pnpm build (883s, clean exit)

Risks and Mitigations

  • Highest risk area: A genuinely fatal error without runLevelError being set, where finalAssistantVisibleText contains only a partial/placeholder message. Mitigation: the !runLevelError guard prevents this — provider errors, context overflows, and abort/timeout scenarios all set runLevelError.
  • Compatibility impact: None. This is a pure relaxation of the fatal classification — runs that were previously error may become ok, but runs that were ok remain ok. No config, migration, or SDK changes.

Security Impact

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Human Verification

AI Assistance 🤖

Related to #96255

@evan-YM evan-YM changed the title [AI] fix(cron): classify recovered agentTurn as non-fatal when finalAssistantVisibleText exists fix(cron): classify recovered agentTurn as non-fatal when finalAssistantVisibleText exists Jun 24, 2026
@clawsweeper

clawsweeper Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Codex review: found issues before merge. Reviewed July 1, 2026, 5:20 AM ET / 09:20 UTC.

Summary
The branch adds a finalAssistantVisibleText recovery gate to cron isolated-agent payload outcome classification and updates resolver tests so recovered error payloads can deliver final assistant text.

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.

  • Recovery And Delivery Decisions: 1 gate added; 1 selector widened; 2 fatal-control tests rebaselined. The diff changes both cron fatality classification and success announce payload selection, so maintainers should review upgrade and delivery semantics before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #94846
Summary: This PR is a candidate fix for the canonical recovered isolated-cron tool-error delivery skip, but it overlaps sibling PRs and currently uses broader recovery semantics than the safer canonical path.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🦞 diamond lobster
Patch quality: 🧂 unranked krab
Result: blocked by patch quality or review findings.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Restrict the recovery gate to proven recovered tool-warning or metadata-backed non-terminal errors and restore provider/plain/all-error fatal controls.
  • Coordinate with the canonical issue's sibling PRs so maintainers land one tested shape.

Mantis proof suggestion
A real no-preference channel smoke would materially show whether recovered cron delivery sends final assistant text without hiding genuine fatal errors. A maintainer can ask Mantis to capture proof by posting this exact PR comment:

@openclaw-mantis slack desktop smoke: verify a scheduled isolated cron run with a recovered tool error delivers final assistant text and still reports a genuine fatal error.

Risk before merge

  • [P1] Merging as-is can mark plain/provider/all-error payloads as recovered whenever final assistant text exists, causing cron to report success and deliver partial or misleading text instead of surfacing a fatal error.
  • [P1] The diff changes both persisted cron run status and which payload reaches normal delivery, so a bad recovery predicate can create session-state drift and message-delivery confusion for scheduled jobs.
  • [P1] Several open PRs target the same canonical cron bug with different semantics, so maintainers should consolidate on one narrow landing shape before merge.

Maintainer options:

  1. Restrict Recovery Before Merge (recommended)
    Keep the final-answer recovery escape tied to known recovered tool-warning or metadata-backed non-terminal errors and restore fatal controls for provider/plain/all-error payloads.
  2. Consolidate On The Canonical Cron Branch
    Pause this branch if maintainers prefer an overlapping candidate PR after that branch has narrower semantics, current-head proof, and clean review.
  3. Accept Broad Final-Text Recovery Deliberately
    Maintainers could intentionally accept final assistant text as a universal recovery signal only with explicit rationale for status, diagnostics, and delivery behavior.

Next step before merge

  • [P2] Needs author or maintainer revision to narrow the recovery predicate and choose the canonical branch among overlapping cron fixes; this is not a safe automatic repair while landing semantics remain unsettled.

Security
Cleared: No concrete security or supply-chain issue was found; the diff is limited to cron helper logic and tests.

Review findings

  • [P1] Keep final-answer recovery scoped to non-terminal errors — src/cron/isolated-agent/helpers.ts:300-303
Review details

Best 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:

  • [P1] Keep final-answer recovery scoped to non-terminal errors — src/cron/isolated-agent/helpers.ts:300-303
    This gate clears hasFatalStructuredErrorPayload whenever final assistant text exists, regardless of what the error payload was. The updated tests now mark model provider unreachable and all-error payloads as recovered, so cron can report success and deliver partial/final text instead of surfacing a real fatal error; restrict this to recovered tool-warning or metadata-backed non-terminal shapes.
    Confidence: 0.93

Overall correctness: patch is incorrect
Overall confidence: 0.92

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against f3ac874fd215.

Label changes

Label justifications:

  • P2: The PR targets a bounded scheduled-cron delivery/status bug with real operator impact but limited blast radius.
  • merge-risk: 🚨 message-delivery: The diff changes which recovered or fatal cron outputs can reach normal delivery and can send partial or misleading final text for real errors.
  • merge-risk: 🚨 session-state: The diff changes fatal-versus-ok cron outcome classification, affecting persisted run status, diagnostics, and operator trust.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🦞 diamond lobster and patch quality is 🧂 unranked krab.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (terminal): The PR body includes after-fix terminal output for five resolver scenarios plus unit-test and build output; it is sufficient helper-level behavior proof, though not full live cron/channel proof.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix terminal output for five resolver scenarios plus unit-test and build output; it is sufficient helper-level behavior proof, though not full live cron/channel proof.
Evidence reviewed

PR surface:

Source +13, Tests +67. Total +80 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 16 3 +13
Tests 1 78 11 +67
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 94 14 +80

What I checked:

  • Repository policy read: Root AGENTS.md was read fully and applied; no scoped AGENTS.md exists under src/cron, so root deep-review and merge-risk guidance controls this review. (AGENTS.md:1, f3ac874fd215)
  • PR head adds broad recovery gate: PR head adds hasRecoveredByFinalAnswer with only no run-level error, no fatal failure signal, and non-empty final text checks; it is not tied to tool-warning or non-terminal metadata. (src/cron/isolated-agent/helpers.ts:300, 3de7817e6f7f)
  • PR head rebaselines fatal controls: The PR changes the model provider unreachable case and the all-error-payload case from fatal to recovered final text, which demonstrates the over-broad predicate. (src/cron/isolated-agent.helpers.test.ts:146, 3de7817e6f7f)
  • Current main preserves fatal error behavior: Current main keeps real trailing errors fatal when final assistant text exists and returns the last error payload when all payloads are errors. (src/cron/isolated-agent.helpers.test.ts:146, f3ac874fd215)
  • Runtime impact reaches delivery and persisted status: run.ts uses hasFatalStructuredErrorPayload to return before normal dispatchCronDelivery, so changing the predicate affects both persisted cron status and user-visible delivery. (src/cron/isolated-agent/run.ts:1284, f3ac874fd215)
  • Latest release still has the narrow current behavior: Latest release v2026.6.11 still requires preferFinalAssistantVisibleText for recovered tool-warning handling and still has the fatal-control tests, so this is not already implemented on main or shipped. (src/cron/isolated-agent/helpers.ts:289, e085fa1a3ffd)

Likely related people:

  • sercada: Commit 0c7220f added fatal structured-error completion-announce suppression across the same helper, runner, and tests. (role: introduced adjacent fatal-delivery behavior; confidence: high; commits: 0c7220f5da78; files: src/cron/isolated-agent/helpers.ts, src/cron/isolated-agent/run.ts, src/cron/isolated-agent/run.message-tool-policy.test.ts)
  • steipete: Commit c8a953a added the cron final-output-over-tool-warning behavior that this PR extends. (role: adjacent recovery behavior contributor; confidence: high; commits: c8a953af9371; files: src/cron/isolated-agent/helpers.ts, src/cron/isolated-agent.helpers.test.ts)
  • welfo-beo: Commit 81c7304 introduced cron final announce delivery handling involving finalAssistantVisibleText in this resolver path. (role: adjacent final-assistant delivery contributor; confidence: medium; commits: 81c7304a18b8; files: src/cron/isolated-agent/helpers.ts, src/cron/isolated-agent.helpers.test.ts, src/cron/isolated-agent/run.ts)
  • vincentkoc: Commit e085fa1 carried the current cron helper, runner, and tests into the latest release tag and is part of the recent history around this surface. (role: recent area contributor; confidence: medium; commits: e085fa1a3ffd; files: src/cron/isolated-agent/helpers.ts, src/cron/isolated-agent/run.ts, src/cron/isolated-agent.helpers.test.ts)
  • Brian Snyder: Current-main blame for the relevant helper and fatal-delivery branch points to commit 63dc920, though the commit title suggests broad unrelated carry-forward rather than original design ownership. (role: recent current-main contributor; confidence: low; commits: 63dc9201c6b6; files: src/cron/isolated-agent/helpers.ts, src/cron/isolated-agent/run.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. labels Jun 24, 2026
@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. label Jun 24, 2026
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Jun 24, 2026
…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]>
@evan-YM
evan-YM force-pushed the fix/cron-recovered-final-answer-96255 branch from 3f42f88 to 3de7817 Compare June 24, 2026 07:23
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jun 24, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. label Jun 24, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 24, 2026
@vincentkoc

Copy link
Copy Markdown
Member

maintainer closeout: this candidate is not safe to land.

finalAssistantVisibleText is not proof that a prior failure recovered. The changed tests explicitly reclassify model provider unreachable and all-error payloads as successful delivery, which can hide provider failures and unresolved mutating tool actions behind success-looking assistant prose.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: S status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants