fix(tasks): reconcile stale subagent tasks when backing CLI child is terminal (fixes #92285)#92454
Conversation
…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.
|
Codex review: needs real behavior proof before merge. Reviewed June 23, 2026, 6:17 PM ET / 22:17 UTC. Summary 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.
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:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest 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:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against b08d901dd2fc. Label changesLabel justifications:
Evidence reviewedPR surface: Source +65, Tests +150. Total +215 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
|
…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)
|
@clawsweeper re-review Addressed review findings:
|
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
@clawsweeper re-review |
…le-taskflow-reconcile
…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'
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
…le-taskflow-reconcile
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
…le-taskflow-reconcile
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
Summary
runIdandownerKeywith their parent subagent task, but task maintenance only checkshasBackingSessionand skips stale childless parent tasks. The parent and its mirrored TaskFlow row remain "running" indefinitely after the CLI child exits.hasBackingSessiongates the existing orphan check, but a stale parent with a dead child has no session to back it.runIdandownerKey. When found, terminalize both the parent task row and the mirrored TaskFlow row.src/tasks/task-registry.ts— addreconcileStaleParentSubagentTaskFromScopedTerminalCliChildlogic that detects the runId/ownerKey match and terminalizes parent + mirrored flowReproduction
hasBackingSession: truefrom the stale child ref → skipped. Parent + mirrored TaskFlow remain "running".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.tsEvidence before fix:
Evidence after fix:
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
runId/ownerKeyrelationship between parent and child may not be durable in all edge casesMitigation: 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.
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)
Scope (select all touched areas)
Regression Test Plan
node scripts/run-vitest.mjs src/tasks/task-registry.maintenance.issue-60299.test.ts— 23 assertions covering the full reconciliation matrixReview Findings Addressed
N/A (initial submission — this push is current with upstream/main, no merge conflicts)
Linked Issue/PR
Fixes #92285