Fix delegation link loss across interrupt/resume; type NewTaskTool provider call - #18
Merged
easonLiangWorldedtech merged 1 commit intoAug 16, 2026
Conversation
…ovider call ## Problem A/C — delegation link lost across interrupt/resume When a delegated child is interrupted (cancelTask / evictCurrentTask), the parent's `awaitingChildId` link is preserved only while the parent is still `delegated`. After a crash or resume cycle the parent can be left `active` with no `awaitingChildId`, so when the user resumes the child, AttemptCompletionTool refuses to route its completion back (it requires `parent.awaitingChildId === this child`). The result: a resumed subtask's result is silently stranded and never reported to the parent. Fix: re-establish the link in `createTaskWithHistoryItem` (the common funnel for every resume path) when resuming an *interrupted* child. New private helper `reestablishDelegationLinkOnResume` transitions a demoted `active` parent back to `delegated`, gated so it: - skips children whose delegation was intentionally severed (`cancelledDelegationChildIds`), - never clobbers a live delegation to a different child, - only performs the legal `active -> delegated` transition. Non-fatal: any failure is logged and the resume proceeds without the link. Because AttemptCompletionTool already accepts an `active` parent whose `awaitingChildId` matches, routing (Problem C) works automatically once the link is restored. ## Problem D — remove `as any` in NewTaskTool `task.providerRef` is a `WeakRef<ClineProvider>`, so after the null-check `provider` is already typed `ClineProvider`. The `(provider as any).delegateParentAndOpenChild(...)` cast was unnecessary; it is now a typed method call. This removes the last `as any` in NewTaskTool.ts, so its stale `no-explicit-any` suppression entry is dropped from eslint-suppressions.json (count never increases). ## Tests Added 4 focused regression tests for `reestablishDelegationLinkOnResume` covering: link restored on resume of an interrupted child with a demoted parent; no-op when already delegated to the same child; never clobbers a live delegation to another child; and no reattach for intentionally-severed children.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix delegation link loss across interrupt/resume + type NewTaskTool provider call
Fixes the remaining PR-6 problems A, C and D (Problem B was already fixed by #16).
Problem A/C — resumed subtask's result never routes back to its parent
When a delegated child is interrupted (
cancelTask/evictCurrentTask), the parent'sawaitingChildIdlink is preserved only while the parent is stilldelegated. After a crash or resume cycle the parent can be leftactivewith noawaitingChildId, so when the user resumes the child,AttemptCompletionToolrefuses to route its completion back (it requiresparent.awaitingChildId === this child). The result: a resumed subtask's result is silently stranded and never reported to the parent.Fix: re-establish the link in
createTaskWithHistoryItem— the common funnel for every resume path (showTaskWithId, cancel-rehydrate, reopen) — when resuming an interrupted child. New private helperreestablishDelegationLinkOnResumetransitions a demotedactiveparent back todelegated, gated so it:cancelledDelegationChildIds),active → delegatedtransition (the sole valid path inVALID_TRANSITIONS).Non-fatal: any failure is logged and the resume proceeds without the link. Because
AttemptCompletionToolalready accepts anactiveparent whoseawaitingChildIdmatches, routing (Problem C) works automatically once the link is restored — no approval-stranding change needed.Problem D — remove
as anyin NewTaskTooltask.providerRefis aWeakRef<ClineProvider>, so after the null-checkprovideris already typedClineProvider. The(provider as any).delegateParentAndOpenChild(...)cast was unnecessary; it is now a typed method call. This removes the lastas anyinNewTaskTool.ts, so its staleno-explicit-anysuppression entry is dropped fromeslint-suppressions.json(suppression counts never increase).Tests
4 focused regression tests for
reestablishDelegationLinkOnResume:Verification
pnpm run check-types— 11/11 tasks successfuleslint-suppressions.jsondiff is a single 5-line deletion of the now-stale entry