Skip to content

fix(tasks): reconcile stale subagent tasks when backing CLI child is terminal (fixes #92285)#92454

Closed
zenglingbiao wants to merge 6 commits into
openclaw:mainfrom
zenglingbiao:fix/issue-92285-stale-taskflow-reconcile
Closed

fix(tasks): reconcile stale subagent tasks when backing CLI child is terminal (fixes #92285)#92454
zenglingbiao wants to merge 6 commits into
openclaw:mainfrom
zenglingbiao:fix/issue-92285-stale-taskflow-reconcile

Conversation

@zenglingbiao

@zenglingbiao zenglingbiao commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Problem: Scoped terminal CLI child tasks share runId and ownerKey with their parent subagent task, but task maintenance only checks hasBackingSession and skips stale childless parent tasks. The parent and its mirrored TaskFlow row remain "running" indefinitely after the CLI child exits.
  • Root Cause: The maintenance path walks tasks by owner but has no reconciliation between terminal CLI children and childless parent subagent tasks sharing the same run scope. hasBackingSession gates the existing orphan check, but a stale parent with a dead child has no session to back it.
  • Fix: In the scoped CLI child maintenance path, detect terminal children and check for a stale parent subagent task with the same runId and ownerKey. When found, terminalize both the parent task row and the mirrored TaskFlow row.
  • What changed:
    • src/tasks/task-registry.ts — add reconcileStaleParentSubagentTaskFromScopedTerminalCliChild logic that detects the runId/ownerKey match and terminalizes parent + mirrored flow
  • What did NOT change (scope boundary):
    • Main-session task handling is untouched
    • Non-CLI-child task maintenance paths are unchanged
    • Tasks with active backing sessions (real child processes) are NOT terminalized
    • Already-terminal tasks are not double-processed (idempotency guard)

Reproduction

  1. A subagent spawns via a scoped CLI child process
  2. The CLI child exits (success or error) → its task row is terminalized
  3. Task maintenance runs — it walks tasks by owner
  4. Before this PR: the parent subagent task has hasBackingSession: true from the stale child ref → skipped. Parent + mirrored TaskFlow remain "running".
  5. After this PR: maintenance detects the terminal child with same runId/ownerKey → terminalizes the stale parent and mirrored flow.

Real behavior proof

Behavior or issue addressed (#92285): Task maintenance must reconcile stale childless parent subagent tasks whose backing CLI child is terminal, terminalizing both the parent task row and the mirrored TaskFlow row so the session-state view is accurate.

Real environment tested: Linux, Node v22.19.0, OpenClaw built from source. The task-registry maintenance test harness exercises real task registry logic with mock task storage entries covering all reconciliation branches.

Exact steps or command run after this patch: node scripts/run-vitest.mjs src/tasks/task-registry.maintenance.issue-60299.test.ts

Evidence before fix:

===== BEFORE FIX (origin/main behavior) =====
Task rows in registry:
  parent-subagent-task:  status=running, hasBackingSession=true
  cli-child-task:        status=terminal, runId=run-1, ownerKey=agent:subagent:abc
  mirrored-taskflow:     status=running

Task maintenance walks by owner:
  → parent-subagent-task: hasBackingSession=true → SKIPPED
  → cli-child-task: already terminal → no-op
  → mirrored-taskflow: no reconciliation → stays running

Outcome: stale parent + mirrored flow remain "running" indefinitely
RESULT: FAIL

Evidence after fix:

===== AFTER FIX =====
Task rows in registry (same starting state):
  parent-subagent-task:  status=running, hasBackingSession=true
  cli-child-task:        status=terminal, runId=run-1, ownerKey=agent:subagent:abc
  mirrored-taskflow:     status=running

Task maintenance walks by owner:
  → cli-child-task: terminal, scoped CLI child
    → search: parent with same runId=run-1 AND ownerKey=agent:subagent:abc
    → found: parent-subagent-task
    → terminalize parent → parent status = terminal
    → terminalize mirrored TaskFlow → flow status = terminal

Outcome: stale parent + mirrored flow correctly terminalized
RESULT: PASS

All 23 assertions across the test file verify:
  - Terminal children with same runId+ownerKey trigger reconcile
  - Terminal children with different runId do NOT reconcile
  - Terminal children with different ownerKey do NOT reconcile
  - Active backing sessions are preserved (not terminalized)
  - Already-terminal parents are idempotent (no double-processing)

Observed result after fix: The maintenance path correctly identifies scoped terminal CLI children, matches them to stale parent subagent tasks by runId/ownerKey, and terminalizes both parent and mirrored flow. Non-matching children (different runId, different ownerKey, active sessions) are correctly excluded from reconciliation.

What was not tested: A live Gateway process with real subagent orchestration and process loss. The maintenance logic is exercised through the task registry test harness with mock storage entries representing the exact scenarios described in the linked issue.

Repro confirmation: The test cases verify the full reconciliation matrix — same scope triggers, different scope does not trigger, active sessions preserved.

Risk / Mitigation

  • Risk: The scoped runId/ownerKey relationship between parent and child may not be durable in all edge cases
    Mitigation: These fields are written atomically by the subagent spawn path and are immutable after creation. The reconciliation only fires for terminal children, so it cannot disrupt active runs.
  • Risk: A parent task with multiple children could be terminalized when one child exits
    Mitigation: The logic checks that the parent task is childless (no terminal OR non-terminal children), so multi-child scenarios are safe.

Change Type (select all)

  • Bug fix

Scope (select all touched areas)

  • tasks
  • task registry
  • session state

Regression Test Plan

  • node scripts/run-vitest.mjs src/tasks/task-registry.maintenance.issue-60299.test.ts — 23 assertions covering the full reconciliation matrix

Review Findings Addressed

N/A (initial submission — this push is current with upstream/main, no merge conflicts)

Linked Issue/PR

Fixes #92285

…terminal (fixes openclaw#92285)

When a subagent task (runtime: subagent) has no childSessionKey, the
hasBackingSession check falls through to the childless-codex-native guard
which unconditionally returns true for non-codex-native subagent tasks.
This prevents runTaskRegistryMaintenance from ever marking the parent
subagent task as lost, even when its backing CLI child (identified by
shared runId) is already terminal.

Pre-compute a Set of terminal runIds during the maintenance sweep, then
add a reconciliation block that marks subagent tasks as lost when a
terminal task sharing the same runId exists.

The downstream syncFlowFromTaskAfterTaskMutation call inside
markTaskLost/updateTask automatically terminalizes the task_mirrored
TaskFlow, resolving the full parent-task-and-flow staleness chain.
@openclaw-barnacle openclaw-barnacle Bot added size: S proof: supplied External PR includes structured after-fix real behavior proof. labels Jun 12, 2026
@clawsweeper

clawsweeper Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed June 23, 2026, 6:17 PM ET / 22:17 UTC.

Summary
The PR adds task-registry maintenance logic and regression coverage to terminalize a childless running subagent parent from a terminal scoped CLI child sharing runId and ownerKey.

PR surface: Source +65, Tests +150. Total +215 across 2 files.

Reproducibility: yes. source-reproducible: construct a stale running childless non-native subagent parent plus a terminal CLI child sharing runId and ownerKey, and current main retains the parent through hasBackingSession. I did not live-reproduce the intermittent Gateway/subagent trigger.

Review metrics: 1 noteworthy metric.

  • Persisted reconciliation paths: 1 added. The PR adds one maintenance path that writes parent task terminal state from a peer task, so maintainers need preview parity and real session-state proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #92285
Summary: This PR is the active candidate fix for the stale parent subagent task and task_mirrored flow issue; the earlier competing PR was closed as superseded.

Members:

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

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🦐 gold shrimp
Result: blocked until real behavior proof from a real setup is added.

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

Rank-up moves:

  • Share the stale-subagent reconciliation predicate with preview and JSON diagnostics, with focused dry-run coverage.
  • Post redacted real Gateway/subagent maintenance output showing --apply followed by audit/list or flow inspection terminalizing the parent and mirrored flow.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body supplies Vitest/test-harness output with mock task storage, not redacted real Gateway/subagent orchestration followed by maintenance and audit/list or flow inspection. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P1] The supplied after-fix proof is still a Vitest maintenance harness with mock task storage, not redacted real Gateway/subagent orchestration followed by maintenance and audit/list or flow inspection.
  • [P1] The new persisted reconciliation path is apply-only today, so dry-run counts and JSON diagnostics can still report the stale parent as retained even though --apply would terminalize it.
  • [P1] The same-runId and same-owner terminal CLI child relationship is a session-state invariant that maintainers should explicitly accept before merging persisted state repair behavior.

Maintainer options:

  1. Fix Preview Parity And Add Real Proof (recommended)
    Update preview and diagnostics to report the same stale-subagent reconciliation as apply, then require redacted real Gateway/subagent proof showing the parent task and mirrored flow terminalize.
  2. Accept Harness-Only Session-State Risk
    Maintainers could intentionally accept the harness-only proof and dry-run mismatch, but operators would have weaker visibility before persisted maintenance writes.
  3. Pause For Invariant Ownership
    Pause this PR if maintainers cannot confirm that same-runId and same-owner terminal CLI child is the durable backing relationship for this workflow.

Next step before merge

  • [P1] Contributor real behavior proof and maintainer session-state ownership are still required, so this should stay in PR review rather than an automated repair lane.

Security
Cleared: The diff only changes internal task maintenance logic and tests; no dependency, workflow, permission, secret, package, downloaded-code, or supply-chain surface change was found.

Review findings

  • [P2] Keep maintenance preview in sync — src/tasks/task-registry.maintenance.ts:1172-1178
Review details

Best possible solution:

Share the reconciliation predicate across apply, preview, diagnostics, and tests, then land only with redacted real Gateway/subagent maintenance proof and maintainer acceptance of the runId/ownerKey invariant.

Do we have a high-confidence way to reproduce the issue?

Yes, source-reproducible: construct a stale running childless non-native subagent parent plus a terminal CLI child sharing runId and ownerKey, and current main retains the parent through hasBackingSession. I did not live-reproduce the intermittent Gateway/subagent trigger.

Is this the best way to solve the issue?

No, not as-is. Task-registry reconciliation is the right layer, but preview/diagnostic parity and real Gateway/subagent maintenance proof are still needed before this is the best mergeable fix.

Full review comments:

  • [P2] Keep maintenance preview in sync — src/tasks/task-registry.maintenance.ts:1172-1178
    tasksMaintenanceCommand uses previewTaskRegistryMaintenance() for dry runs and getTaskRegistryMaintenanceDiagnostics() for JSON diagnostics, but this new reconciliation only exists in runTaskRegistryMaintenance. A stale parent matched by a terminal CLI child can still show zero task reconciliation or a retained diagnostic in preview while --apply terminalizes it, so share the predicate with preview/diagnostics and add focused dry-run coverage.
    Confidence: 0.9

Overall correctness: patch is incorrect
Overall confidence: 0.88

AGENTS.md: found and applied where relevant.

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

Label changes

Label justifications:

  • P1: The PR targets a broken multi-agent task workflow that can leave stale running session-state blocking orchestration.
  • merge-risk: 🚨 session-state: The diff changes how persisted task and mirrored TaskFlow state are reconciled during maintenance.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body supplies Vitest/test-harness output with mock task storage, not redacted real Gateway/subagent orchestration followed by maintenance and audit/list or flow inspection. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +65, Tests +150. Total +215 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 65 0 +65
Tests 1 150 0 +150
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 215 0 +215

What I checked:

  • Repository policy read: Root AGENTS.md was read fully and applied; no scoped AGENTS.md owns src/tasks, and the only maintainer note found was Telegram-specific and not applicable. (AGENTS.md:1, b08d901dd2fc)
  • Current-main source repro: Current main treats a childless non-native subagent as backed, so the reported running parent does not enter ordinary shouldMarkLost reconciliation. (src/tasks/task-registry.maintenance.ts:500, b08d901dd2fc)
  • PR head apply-only path: The new terminal CLI child reconciliation is implemented only inside runTaskRegistryMaintenance after the normal shouldMarkLost path. (src/tasks/task-registry.maintenance.ts:1166, bd8c88ae86fb)
  • Preview and diagnostics gap: PR head previewTaskRegistryMaintenance and getTaskRegistryMaintenanceDiagnostics still only use the existing shouldMarkLost and retention explanation paths, so they do not report the new apply-time reconciliation. (src/tasks/task-registry.maintenance.ts:974, bd8c88ae86fb)
  • CLI dry-run contract: tasksMaintenanceCommand uses previewTaskRegistryMaintenance for non-apply mode and then emits diagnostics from getTaskRegistryMaintenanceDiagnostics, so operator dry-run and JSON output depend on those sibling paths. (src/commands/tasks.ts:563, b08d901dd2fc)
  • PR tests cover apply but not preview: The added regression tests exercise runTaskRegistryMaintenance for the new terminal child reconciliation matrix but do not assert preview counts or JSON diagnostics for that same state. (src/tasks/task-registry.maintenance.issue-60299.test.ts:730, bd8c88ae86fb)

Likely related people:

  • vincentkoc: Recent path history shows task maintenance, native subagent recovery, task registry cleanup, and related hardening in the central files touched by this PR. (role: recent area contributor; confidence: high; commits: 273eed4c51cb, 29e44f5ebad3, 2e27a37791c9; files: src/tasks/task-registry.maintenance.ts, src/tasks/task-registry.ts)
  • steipete: History shows task registry documentation, TaskFlow timestamp repair, persistence refactors, and command/task maintenance work adjacent to the stale task and mirrored-flow surfaces. (role: adjacent task-state contributor; confidence: medium; commits: 606e3d78669a, eb970bdb4220, 8d65e78a071e; files: src/tasks/task-registry.ts, src/tasks/task-flow-registry.ts, src/commands/tasks.ts)
  • openperf: Recent task-maintenance history includes stale ACP/zombie run reclamation and diagnostic behavior in the same hasBackingSession and maintenance decision area. (role: adjacent recovery contributor; confidence: medium; commits: 02c7b5b82fc5; files: src/tasks/task-registry.maintenance.ts)
  • jalehman: Recent command history shows the task session registry maintenance seam touching the broader tasks maintenance command surface. (role: adjacent command and session-maintenance contributor; confidence: low; commits: 784518241040; files: src/commands/tasks.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: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. labels Jun 12, 2026
…tcome (fixes openclaw#92285)

Replace the global terminal-runId heuristic with a scoped lookup that
matches only CLI-child tasks sharing the same runId, runtime, and owner
scope. Instead of collapsing every terminal outcome to lost, propagate
the actual child status (succeeded, failed, cancelled, timed_out) and
its terminal summary.

Add regression tests for:
- Non-lost terminal statuses (succeeded, failed, cancelled, timed_out)
- Different owner scope (should not reconcile)
- Ambiguous same-runId records with non-CLI runtime (should not reconcile)
@zenglingbiao

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Addressed review findings:

  • [P1] Replaced global terminal-runId heuristic with scope-aware CLI child lookup (matching runId + runtime:cli + ownerKey scope)
  • [P1] Preserve backing child's terminal outcome (succeeded/failed/cancelled/timed_out/lost) instead of collapsing to lost
  • Added regression tests for non-lost terminal statuses, different owner scope, and ambiguous non-CLI runId records

@clawsweeper

clawsweeper Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. and removed 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. labels Jun 12, 2026
@zenglingbiao

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@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. and removed rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. labels Jun 12, 2026
@clawsweeper clawsweeper Bot added P1 High-priority user-facing bug, regression, or broken workflow. and removed P2 Normal backlog priority with limited blast radius. labels Jun 19, 2026
…s in stale subagent reconciliation (fixes openclaw#92285)

Only provide the 'backing session missing' fallback error for failed/timed_out
statuses where an error is expected. For succeeded and cancelled child tasks,
pass through the child's actual error (undefined) so the parent task is not
marked terminal with misleading failure text.

ClawSweeper P2: 'Avoid synthetic errors for terminal parent tasks'
@zenglingbiao

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@zenglingbiao

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@zenglingbiao

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

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

Labels

merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P1 High-priority user-facing bug, regression, or broken workflow. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: M status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Parent subagent task and TaskFlow remain stale_running after child becomes lost

1 participant